home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / xio.c < prev   
C/C++ Source or Header  |  1996-07-24  |  89KB  |  2,625 lines

  1. /*
  2.  * static char *rcsid_xio_c =
  3.  *   "$Id: xio.c,v 1.44 1996/03/06 06:41:40 master Exp $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #ifdef ds
  30. #include <stddef.h>
  31. #endif
  32. #include <bitmaps.h>
  33. #include <global.h>
  34. #ifndef __CEXTRACT__
  35. #include <sproto.h>
  36. #endif
  37. #include <xio.h>
  38. #include <spells.h>
  39. #include <skills.h>
  40. #include <object.h>
  41. #include <stdarg.h>
  42.  
  43. static char font_text_stats[]="8x13";
  44. static char font_text_info[]="8x13";
  45. static char font_inv_text[]="8x13";
  46.  
  47. #ifdef USE_BUTTONS
  48. static char *dirnames [NUMDIRBUTTS] = {
  49.         "NW","No","NE","We","Br","Ea","SW","So","SE"};
  50.  
  51. static char *opnames [NUMOPBUTTS] = {
  52.         "Change","Apply","Peace ","Talk  "};
  53.  
  54. int dirX [NUMDIRBUTTS] = {186, 216, 246,186,216,246,186,216,246};
  55. int dirY [NUMDIRBUTTS] = {1,1,1,21,21,21,41,41,41};
  56. int dirW = 20;
  57.  
  58. int opX [NUMOPBUTTS] = {158,218,158,218};
  59. int opY [NUMOPBUTTS] = {61,61,81,81};
  60. #endif
  61.  
  62.  
  63.  
  64. int IOerrors(Display *d) {
  65.   player *pl;
  66.   char buf[MAX_BUF];
  67.  
  68.   LOG(llevError,"Fatal error on display.\n");
  69. /* Give pass 1 to emergency save - this tells it that it is only a backup
  70.  * copy should be made, and that it shouldn't free any data.  Since we want
  71.  * to try and continue from this error, that is what we want.
  72.  */
  73.   emergency_save(1);
  74.  
  75.   if(editor)
  76.     exit(-1);
  77.   for(pl=first_player;pl!=NULL;pl=pl->next)
  78.     if(pl->gdisp==d)
  79.       break;
  80.   if(pl==NULL)
  81.     return 0;
  82.  
  83.   save_player(pl->ob, 1);
  84.  
  85.   LOG(llevError,"Player %s lost the display.\n",pl->name);
  86.   (void) sprintf(buf,"%s lost connection.",pl->name);
  87.   remove_lock(pl);
  88.  
  89.   /* prevent updating inventory of player for whom there is no longer a
  90.   ** functional display */
  91.   pl->freeze_inv = 1;
  92.  
  93.   if(pl->ob->map!=NULL)
  94.     pl->ob->map->players--;
  95.   if(pl->ob->state== ST_PLAYING ||pl->ob->state==ST_CHANGE_CLASS ||
  96.     pl->ob->state==ST_CONFIGURE)
  97.         if( !QUERY_FLAG(pl->ob,FLAG_REMOVED)) remove_ob(pl->ob);
  98.  
  99.  
  100.   destroy_object(pl->ob);
  101.   free_object(pl->ob);
  102.  
  103.   free_player(pl);
  104. /*
  105.  * If in a server-mode, I assume a shell-script is restarting it.
  106.  * Thus I exit if I can, since some variables can be messed up by the
  107.  * longjmp() below.
  108.  *
  109.  * If we are in server mode, don't exit.  This way, maps don't reset.
  110.  */
  111.   if(first_player==NULL && server_mode !=SERVER_ENABLED) {
  112.     LOG(llevError,"Only 1 player - exiting the program.\n");
  113.     exit(0);
  114.   }
  115.   new_draw_info(NDI_UNIQUE | NDI_ALL, 5, NULL, buf);
  116.  
  117. #ifdef LONGJUMP
  118.   longjmp(jump_addr,1);
  119. #else
  120.   fatal_signal(0, 1);
  121. #endif
  122.   return 0;
  123. }
  124.  
  125. int Xerrors(Display *d,XErrorEvent *err) {
  126.   char buf[MAX_BUF];
  127.  
  128.   XGetErrorText(d,err->error_code,buf,MAX_BUF);
  129.   LOG(llevError,"Error code %s\n",buf);
  130.   return 0;
  131. }
  132.  
  133. void setuperrors() {
  134.   XSetIOErrorHandler(IOerrors);
  135.   XSetErrorHandler(Xerrors);
  136. }
  137.  
  138. int get_root_display(player *p, char *display) {
  139. #ifdef HAVE_SAVE_UID
  140.   uid_t olduid;
  141. #endif
  142.   char *cp;
  143. #if 0
  144.   XSetWindowAttributes attr;
  145. #endif
  146.  
  147. #ifdef HAVE_SAVE_UID
  148.   olduid = geteuid();        /* I like to run it suid :) */
  149.   setuid(getuid());        /* Have to this to open display, */
  150.                 /* if anyone is using xauth like me. */
  151. #endif
  152.  
  153.   p->gdisp=XOpenDisplay(display);
  154.  
  155.   if (!p->gdisp) {
  156.     sprintf(errmsg, "Can't open display %s.", display);
  157.     return 1;
  158.   }
  159.  
  160.   if ((cp=XGetDefault(p->gdisp,name,"splitwindow")) != NULL)
  161.     if (!strcmp("on",cp) || !strcmp("yes",cp))
  162.       p->split_window = 1;
  163.     else if (!strcmp("off",cp) || !strcmp("no",cp))
  164.       p->split_window = 0;
  165.   if ((cp=XGetDefault(p->gdisp,"crossfire","pixmap")) != NULL)
  166.     if (!strcmp("on",cp) || !strcmp("yes",cp))
  167.       p->use_pixmaps = 1;
  168.     else if (!strcmp("off",cp) || !strcmp("no",cp))
  169.       p->use_pixmaps = 0;
  170.  
  171.  
  172. #ifdef HAVE_SAVE_UID
  173.   setuid(olduid);        /* Back to owner of suid crossfire */
  174. #else
  175.   setuid(geteuid());        /* We want both ruid == euid */
  176. #endif
  177.  
  178. /*
  179.   XAutoRepeatOff(p->gdisp);
  180. */
  181.   p->gscreen=DefaultScreen(p->gdisp);
  182.   p->gbackground=WhitePixel(p->gdisp,p->gscreen);
  183.   p->gforeground=BlackPixel(p->gdisp,p->gscreen);
  184.   p->roothint.x=0,p->roothint.y=0;
  185.   p->roothint.width=582+6+INFOCHARS*FONTWIDTH;
  186.   p->roothint.height=482;
  187.   p->roothint.max_width=p->roothint.min_width=p->roothint.width;
  188.   p->roothint.max_height=p->roothint.min_height=p->roothint.height;
  189.   p->roothint.flags=PPosition | PSize;
  190.   if(!p->split_window) {
  191.     p->win_root=XCreateSimpleWindow(p->gdisp,DefaultRootWindow(p->gdisp),
  192.         p->roothint.x,p->roothint.y,p->roothint.width,p->roothint.height,2,
  193.         p->gbackground,p->gforeground);
  194.     p->iscolor=allocate_colors(p->gdisp, p->win_root, p->gscreen,
  195.     &p->colormap, p->discolor);
  196.     if (p->iscolor){
  197.     p->gforeground=p->discolor[0].pixel;
  198.     p->gbackground=p->discolor[8].pixel;
  199.     /* We need to set this here - while we pretend to set it in the
  200.      * XCreateSimpleWindow above, we actually haven't set the colors yet.
  201.      */
  202.     XSetWindowBackground(p->gdisp, p->win_root, p->gforeground);
  203.     XSetWindowBorder(p->gdisp, p->win_root, p->gbackground);
  204.     }
  205.     p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_root,
  206.           (_Xconst char *) crossfire_bits,
  207.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  208.     XSetStandardProperties(p->gdisp,p->win_root,name,name,
  209.                            p->pixmap,gargv,gargc,&(p->roothint));
  210.     p->gc_root=XCreateGC(p->gdisp,p->win_root,0,0);
  211.     XSetForeground(p->gdisp,p->gc_root,p->gforeground);
  212.     XSetBackground(p->gdisp,p->gc_root,p->gbackground);
  213.   }
  214.   if(!p->use_pixmaps)
  215.     p->use_pixmaps = fixfontpath(p->gdisp,p->name);
  216.  
  217.   if(!p->split_window) {
  218.     if(!p->use_pixmaps) {
  219.       p->font=XLoadFont(p->gdisp,font_graphic);
  220.       XSetFont(p->gdisp,p->gc_root,p->font);
  221.     }
  222.     XSelectInput(p->gdisp,p->win_root,KeyPressMask|
  223.                  KeyReleaseMask|ExposureMask|StructureNotifyMask);
  224.     XMapRaised(p->gdisp,p->win_root);
  225.     XNextEvent(p->gdisp,&p->gevent);
  226.   }
  227.   setuperrors();
  228.   return 0;
  229. }
  230.  
  231. int get_game_display(player *p,char *display) {
  232.   char *cp;
  233.    
  234.   p->gamehint.x=305,p->gamehint.y=104;
  235.   p->gamehint.width=269,p->gamehint.height=269;
  236.   p->gamehint.max_width=p->gamehint.min_width=p->gamehint.width;
  237.   p->gamehint.max_height=p->gamehint.min_height=p->gamehint.height;
  238.   p->gamehint.flags=PPosition | PSize;
  239.   p->win_game=XCreateSimpleWindow(p->gdisp,
  240.       p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
  241.       p->gamehint.x,p->gamehint.y,p->gamehint.width,p->gamehint.height,2,
  242.       p->gbackground,p->gforeground);
  243.   p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_game,
  244.           (_Xconst char *) crossfire_bits,
  245.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  246.   if (p->split_window) {
  247.     p->iscolor=allocate_colors(p->gdisp, p->win_game, p->gscreen,
  248.     &p->colormap, p->discolor);
  249.     if (p->iscolor){
  250.     p->gforeground=p->discolor[0].pixel;
  251.     p->gbackground=p->discolor[8].pixel;
  252.     /* We need to set this here - while we pretend to set it in the
  253.      * XCreateSimpleWindow above, we actually haven't set the colors yet.
  254.      */
  255.     XSetWindowBackground(p->gdisp, p->win_game, p->gforeground);
  256.     XSetWindowBorder(p->gdisp, p->win_game, p->gbackground);
  257.     }
  258.   } else if (p->iscolor) 
  259.     XSetWindowColormap(p->gdisp, p->win_game, p->colormap);
  260.  
  261.   XSetStandardProperties(p->gdisp,p->win_game,"Crossfire",name,
  262.                          p->pixmap,gargv,gargc, &(p->gamehint));
  263.  
  264.   /* Eneq(@csd.uu.se): Has to load the chrfont from the resources here. */
  265.  
  266.   if((cp=XGetDefault(p->gdisp,name,"chrfont"))!=NULL||chrfont!=NULL) {
  267.       XFontStruct *tmp;
  268.  
  269.       if (chrfont!=NULL)
  270.         cp=chrfont;
  271.  
  272.       if ((tmp=XLoadQueryFont(p->gdisp, cp)) != NULL) {
  273.         strcpy (p->font_str, cp);
  274.         XFreeFont(p->gdisp, tmp);
  275.       } else
  276.         LOG(llevError, "Crossfire: Couldn't load font %s.\n", cp);
  277.   }
  278.  
  279.   p->gc_game=XCreateGC(p->gdisp,p->win_game,0,0);
  280.   if (p->iscolor){
  281.      XSetForeground(p->gdisp,p->gc_game,p->discolor[0].pixel);
  282.      XSetBackground(p->gdisp,p->gc_game,p->discolor[12].pixel);
  283.   }
  284.   else{
  285.      XSetForeground(p->gdisp,p->gc_game,p->gforeground);
  286.      XSetBackground(p->gdisp,p->gc_game,p->gbackground);
  287.   }
  288.   XSetGraphicsExposures(p->gdisp, p->gc_game, False);
  289.   if(!p->use_pixmaps) {
  290.     p->game_font=p->font=XLoadFont(p->gdisp,font_graphic);
  291.     XSetFont(p->gdisp,p->gc_game,p->font);
  292.   }
  293.   if (p->color_pixmaps) {
  294.     p->gc_xpm_floor = XCreateGC(p->gdisp,p->win_game,0,0);
  295.     p->gc_xpm_object = XCreateGC(p->gdisp,p->win_game,0,0);
  296.     XSetGraphicsExposures(p->gdisp, p->gc_xpm_floor, False);
  297.     XSetGraphicsExposures(p->gdisp, p->gc_xpm_object, False);
  298.     XSetClipOrigin(p->gdisp, p->gc_xpm_object,
  299.         0, 0);
  300.     p->xpm_pixmap = XCreatePixmap(p->gdisp, RootWindow(p->gdisp,
  301.         DefaultScreen(p->gdisp)), 24, 24, DefaultDepth(p->gdisp,
  302.         DefaultScreen(p->gdisp)));
  303.   }
  304.  
  305.   XSelectInput(p->gdisp,p->win_game,
  306.                ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask);
  307.   XMapRaised(p->gdisp,p->win_game);
  308.   return 0;
  309. }
  310.  
  311. int get_info_display(player *p,char *name) {
  312.   p->infohint.x=579,p->infohint.y=0;
  313.   p->infohint.width=6+INFOCHARS*FONTWIDTH,p->infohint.height=11+p->infolines*13;
  314.   p->infohint.min_width=100;
  315.   p->infohint.min_height=30;
  316.   p->infohint.flags=PPosition | PSize;
  317.   p->win_info=XCreateSimpleWindow(p->gdisp,
  318.       p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
  319.       p->infohint.x,p->infohint.y,p->infohint.width,p->infohint.height,2,
  320.       p->gforeground,p->gbackground);
  321.   if (p->iscolor)
  322.     XSetWindowColormap(p->gdisp, p->win_info, p->colormap);
  323.   p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_info,
  324.           (_Xconst char *) crossfire_bits,
  325.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  326.   XSetStandardProperties(p->gdisp,p->win_info,"Crossfire - text","Crosstext",
  327.              p->pixmap,gargv,gargc,&(p->infohint));
  328.   p->gc_info=XCreateGC(p->gdisp,p->win_info,0,0);
  329.   XSetForeground(p->gdisp,p->gc_info,p->gforeground);
  330.   XSetBackground(p->gdisp,p->gc_info,p->gbackground);
  331.   p->font=XLoadFont(p->gdisp,font_text_info);
  332.   XSetFont(p->gdisp,p->gc_info,p->font);
  333.   XSelectInput(p->gdisp,p->win_info,
  334.                ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
  335.                StructureNotifyMask);
  336.   XMapRaised(p->gdisp,p->win_info);
  337.   return 0;
  338. }
  339.  
  340. void resize_win_info(player *p,XEvent *event) {
  341.   int chars=(event->xconfigure.width/FONTWIDTH)-1;
  342.   int lines=(event->xconfigure.height/FONTHEIGHT);
  343.   int i;
  344.   char **info;
  345.   if(chars==p->infochars&&lines==p->infolines)
  346.     return;
  347.   if(chars<3||lines<3)
  348.     return;
  349.   info=(char **) malloc(sizeof(char *) * lines);
  350.  
  351.   /* If the new window is smaller, we want to lose the oldest lines
  352.    * in the window.  This is not necessarily the same thing as the
  353.    * bottom lines of the display.
  354.    * If the buffer hasn't filled up yet (infofull==0), then
  355.    * the oldes lines are those starting at 0.
  356.    * If in wrap mode, the oldest lines are those after infoline.  If
  357.    * in scroll mode, the oldest are those after infopos.
  358.    * I had to re-write this function pretty majorly to do this.
  359.    * Mark S. Wedel (master@rahul.net)
  360.    */
  361.   if (lines<p->infolines) {
  362.     int diff = p->infolines - lines,start;
  363.  
  364.     if (!p->infofull) {
  365.         if (p->infoline>lines) start=p->infoline-lines;
  366.         else start=0;
  367.     }
  368.     else if (!p->scroll) start = p->infoline + diff;
  369.     else start = p->infopos + diff;
  370.  
  371.     for (i=0; i<lines; i++) {
  372.         info[i]= (char *) malloc(sizeof(char) * (chars+1));
  373.         strncpy(info[i], p->info[(i+start) % p->infolines],chars);
  374.         info[i][chars]='\0';
  375.     }
  376.     if (p->infoline>=lines) p->infoline = lines-1;
  377.     if (p->infopos>=lines) p->infopos = lines-1;
  378.     p->infofull = 0;
  379.  
  380.   }
  381.   else {
  382.   /* If the window is getting bigger, things are a little simpler
  383.    * than above.  However, for the data in scroll mode to make
  384.    * sense, we do need to re-copy it in a make sense way.
  385.    * MSW (master@cats.ucsc.edu)
  386.    */
  387.     int start;
  388.  
  389.     if (!p->infofull) start=0;
  390.     else {
  391.     if (p->scroll)
  392.         start = p->infopos;
  393.     else start = p->infoline;
  394.     /* the way we copy the lines makes it so the oldest is
  395.       * line 0, and the newest is the last line.  so update
  396.      * p->infoline accordingly
  397.      */
  398.     p->infoline = lines-1; 
  399.     p->infopos = lines - 1;
  400.     }
  401.  
  402.     for (i=0; i<p->infolines; i++) {
  403.         info[i]= (char *) malloc(sizeof(char) * (chars+1));
  404.         strncpy(info[i], p->info[(i+start) % p->infolines], chars);
  405.         info[i][chars]='\0';
  406.     }
  407.     for (i=p->infolines; i<lines; i++) {
  408.         info[i]= (char *) malloc(sizeof(char) * (chars+1));
  409.         info[i][0]='\0';
  410.     }
  411.     p->infofull = 0;
  412.   }
  413.   for(i=0;i<p->infolines;i++)
  414.     free(p->info[i]);
  415.   free(p->info);
  416.  
  417.   if(p->writing>=chars)
  418.     p->writing=chars-1;
  419.   p->info=info;
  420.   p->infochars=chars;
  421.   p->infolines=lines;
  422.   refresh_win_info(p->ob);
  423. }
  424.  
  425. void resize_win_inv(player *p,XEvent *event) {
  426.   int x=event->xconfigure.width;
  427.   int y=event->xconfigure.height;
  428.   int lines=(y-FONTHEIGHT-8)/24;
  429.  
  430.   if(x==p->invhint.x&&y==p->invhint.y)
  431.     return;
  432.   if(lines>MAX_INV_SIZE)
  433.     lines=MAX_INV_SIZE;
  434.   p->inv_size=lines;
  435.   if (p->show_inv_icon)
  436.     p->inv_chars=(x-88)/FONTWIDTH;
  437.   else
  438.     p->inv_chars=(x-60)/FONTWIDTH;
  439.   p->invhint.width=x;
  440.   p->invhint.height=y;
  441.   p->barlength_inv=lines*24;
  442.   sprintf(p->format_inv,"%%-%d.%ds%%-6s",p->inv_chars-6,p->inv_chars-6);
  443.   draw_all_inventory(p->ob);
  444. }
  445.  
  446. void resize_win_look(player *p,XEvent *event) {
  447.   int x=event->xconfigure.width;
  448.   int y=event->xconfigure.height;
  449.   int lines=(y-FONTHEIGHT-8)/24;
  450.   int chars=(x-60)/FONTWIDTH;
  451.   if(x==p->lookhint.x&&y==p->lookhint.y)
  452.     return;
  453.   if(lines>MAX_LOOK_SIZE)
  454.     lines=MAX_LOOK_SIZE;
  455.   p->look_size=lines;
  456.   p->look_chars=chars;
  457.   p->lookhint.width=x;
  458.   p->lookhint.height=y;
  459.   p->barlength_look=lines*24;
  460.   sprintf(p->format_look,"%%-%d.%ds%%-6s",chars-6,chars-6);
  461.   draw_all_look(p->ob);
  462. }
  463.  
  464. int get_message_display(player *p,char *name) { /* Misc-window */
  465.   p->messagehint.x=303,p->messagehint.y=378;
  466.   p->messagehint.width=273,p->messagehint.height=101;
  467.   p->messagehint.max_width=p->messagehint.min_width=p->messagehint.width;
  468.   p->messagehint.max_height=p->messagehint.min_height=p->messagehint.height;
  469.   p->messagehint.flags=PPosition | PSize;
  470.   p->win_message=XCreateSimpleWindow(p->gdisp,
  471.       p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
  472.       p->messagehint.x,p->messagehint.y,p->messagehint.width,
  473.       p->messagehint.height,2,p->gforeground,p->gbackground);
  474.   if (p->iscolor)
  475.     XSetWindowColormap(p->gdisp, p->win_message, p->colormap);
  476.   p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_message,
  477.           (_Xconst char *) crossfire_bits,
  478.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  479.   XSetStandardProperties(p->gdisp,p->win_message,"Crossfire - vitals",
  480.                          "crossvitals",p->pixmap,
  481.                          gargv,gargc,&(p->messagehint));
  482.   p->gc_message=XCreateGC(p->gdisp,p->win_message,0,0);
  483.   XSetForeground(p->gdisp,p->gc_message,p->gforeground);
  484.   XSetBackground(p->gdisp,p->gc_message,p->gbackground);
  485.   p->font=XLoadFont(p->gdisp,font_text_info);
  486.   XSetFont(p->gdisp,p->gc_message,p->font);
  487.   XSelectInput(p->gdisp,p->win_message,
  488.                ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask);
  489.   XMapRaised(p->gdisp,p->win_message);
  490.   return 0;
  491. }
  492.  
  493. int get_inv_display(player *p,char *name) {
  494. #ifdef OBWIN
  495.   p->inv=create_obwin(p,0,0,300,310,p->split_window,"inventory");
  496. #else
  497.   p->invhint.x=0,p->invhint.y=0;
  498.   p->invhint.width=300,p->invhint.height=310;
  499.   p->invhint.min_width=60+10*FONTWIDTH;
  500.   p->invhint.min_height=FONTHEIGHT+8+24*2;
  501.   p->invhint.flags=PPosition | PSize;
  502.   p->win_inv=XCreateSimpleWindow(p->gdisp,
  503.       p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
  504.       p->invhint.x,p->invhint.y,p->invhint.width,p->invhint.height,2,
  505.       p->gforeground,p->gbackground);
  506.   if (p->iscolor)
  507.     XSetWindowColormap(p->gdisp, p->win_inv, p->colormap);
  508.   p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_inv,
  509.           (_Xconst char *) crossfire_bits,
  510.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  511.   XSetStandardProperties(p->gdisp,p->win_inv,"Crossfire - inventory",
  512.                          "crossinventory",p->pixmap,gargv,gargc,
  513.                          &(p->invhint));
  514.   XSelectInput(p->gdisp,p->win_inv,
  515.                ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
  516.                StructureNotifyMask);
  517.   XMapRaised(p->gdisp,p->win_inv);
  518.   p->gc_inv_text=XCreateGC(p->gdisp,p->win_inv,0,0);
  519.   p->gc_inv_icon=XCreateGC(p->gdisp,p->win_inv,0,0);
  520.  
  521.   /* Always create these, even thow we may not need them.  The space they use
  522.    * is probably minimal, and to create/destroy them each time the user
  523.    * switches would get pretty messy.
  524.    */
  525.   p->gc_inv_status_icon = XCreateGC(p->gdisp,p->win_inv,0,0);
  526.   XSetForeground(p->gdisp,p->gc_inv_status_icon,p->gforeground);
  527.   XSetBackground(p->gdisp,p->gc_inv_status_icon,p->gbackground);
  528.   XSetGraphicsExposures(p->gdisp, p->gc_inv_status_icon, False);
  529.  
  530.   XSetForeground(p->gdisp,p->gc_inv_text,p->gforeground);
  531.   XSetBackground(p->gdisp,p->gc_inv_text,p->gbackground);
  532.   XSetForeground(p->gdisp,p->gc_inv_icon,p->gforeground);
  533.   XSetBackground(p->gdisp,p->gc_inv_icon,p->gbackground);
  534.   XSetGraphicsExposures(p->gdisp, p->gc_inv_icon, False);
  535.   p->font=XLoadFont(p->gdisp,font_inv_text);
  536.   XSetFont(p->gdisp,p->gc_inv_text,p->font);
  537.   if(!p->use_pixmaps) {
  538.     p->font=XLoadFont(p->gdisp,font_graphic);
  539.     XSetFont(p->gdisp,p->gc_inv_status_icon,p->font);
  540.     XSetFont(p->gdisp,p->gc_inv_icon,p->font);
  541.   }
  542. #endif
  543.   return 0;
  544. }
  545.  
  546. int get_look_display(player *p,char *name) {
  547.   p->lookhint.x=0,p->lookhint.y=313;
  548.   p->lookhint.width=300,p->lookhint.height=166;
  549.   p->lookhint.min_width=60+10*FONTWIDTH;
  550.   p->lookhint.min_height=FONTHEIGHT+8+24*2;
  551.   p->lookhint.flags=PPosition | PSize;
  552.   p->win_look=XCreateSimpleWindow(p->gdisp,
  553.       p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
  554.       p->lookhint.x,p->lookhint.y,p->lookhint.width,p->lookhint.height,2,
  555.       p->gforeground,p->gbackground);
  556.   if (p->iscolor)
  557.     XSetWindowColormap(p->gdisp, p->win_look, p->colormap);
  558.   p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_look,
  559.           (_Xconst char *) crossfire_bits,
  560.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  561.   XSetStandardProperties(p->gdisp,p->win_look,"Crossfire - look",
  562.                          "crosslook",p->pixmap,gargv,gargc,
  563.                          &(p->lookhint));
  564.   p->gc_look_text=XCreateGC(p->gdisp,p->win_look,0,0);
  565.   p->gc_look_icon=XCreateGC(p->gdisp,p->win_look,0,0);
  566.   XSetForeground(p->gdisp,p->gc_look_text,p->gforeground);
  567.   XSetBackground(p->gdisp,p->gc_look_text,p->gbackground);
  568.   XSetForeground(p->gdisp,p->gc_look_icon,p->gforeground);
  569.   XSetBackground(p->gdisp,p->gc_look_icon,p->gbackground);
  570.   XSetGraphicsExposures(p->gdisp, p->gc_look_icon, False);
  571.   p->font=XLoadFont(p->gdisp,font_inv_text);
  572.   XSetFont(p->gdisp,p->gc_look_text,p->font);
  573.   if(!p->use_pixmaps) {
  574.     p->font=XLoadFont(p->gdisp,font_graphic);
  575.     XSetFont(p->gdisp,p->gc_look_icon,p->font);
  576.   }
  577.   XSelectInput(p->gdisp,p->win_look,
  578.                ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
  579.                StructureNotifyMask);
  580.   XMapRaised(p->gdisp,p->win_look);
  581.   return 0;
  582. }
  583.  
  584. int get_stats_display(player *p,char *name) {
  585.   p->stathint.x=303,p->stathint.y=0;
  586.   p->stathint.width=273,p->stathint.height=100;
  587.   p->stathint.min_width=p->stathint.max_width=p->stathint.width;
  588.   p->stathint.min_height=p->stathint.max_height=p->stathint.height;
  589.   p->stathint.flags=PPosition | PSize;
  590.   p->win_stats=XCreateSimpleWindow(p->gdisp,
  591.       p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
  592.       p->stathint.x,p->stathint.y,p->stathint.width,p->stathint.height,2,
  593.       p->gforeground,p->gbackground);
  594.   if (p->iscolor)
  595.     XSetWindowColormap(p->gdisp, p->win_stats, p->colormap);
  596.   p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_stats,
  597.           (_Xconst char *) crossfire_bits,
  598.       (unsigned int) crossfire_width, (unsigned int)crossfire_height);
  599.   XSetStandardProperties(p->gdisp,p->win_stats,"Crossfire - status",
  600.                          "crosstatus",p->pixmap,gargv,gargc,
  601.                          &(p->stathint));
  602.   p->gc_stats=XCreateGC(p->gdisp,p->win_stats,0,0);
  603.   XSetForeground(p->gdisp,p->gc_stats,p->gforeground);
  604.   XSetBackground(p->gdisp,p->gc_stats,p->gbackground);
  605.   p->font=XLoadFont(p->gdisp,font_text_stats);
  606.   XSetFont(p->gdisp,p->gc_stats,p->font);
  607.   XSelectInput(p->gdisp,p->win_stats,
  608.                KeyPressMask|KeyReleaseMask|ExposureMask);
  609.   XMapRaised(p->gdisp,p->win_stats);
  610.   return 0;
  611. }
  612.  
  613. #ifdef SET_TITLE
  614. void redraw_title(object *pl)
  615. {
  616.   char buf[MAX_BUF];
  617.   if (pl->contr->own_title[0]=='\0')
  618.     sprintf(buf,"Player: %s the %s",pl->name,pl->contr->title);
  619.   else
  620.     sprintf(buf,"Player: %s the %s",pl->name,pl->contr->own_title);
  621.   strcat(buf,"                    ");
  622.   XDrawImageString(pl->contr->gdisp,pl->contr->win_stats,
  623.                   pl->contr->gc_stats,10,10,buf,strlen(buf));
  624. }
  625. #endif /* SET_TITLE */
  626.  
  627. void rangetostring(object *pl,char *obuf)
  628. {
  629.   int chosen_spell;
  630.  
  631.   chosen_spell = (pl->contr->shoottype==range_magic)? pl->contr->chosen_spell :
  632.       pl->contr->chosen_item_spell;
  633.   switch(pl->contr->shoottype) {
  634.    case range_none:
  635.     strcpy(obuf,"Range: nothing");
  636.     break;
  637.    case range_bow: {
  638.      char *s;
  639.      object *op;
  640.      for (op = pl->inv; op; op=op->below)
  641.        if (op->type == BOW && QUERY_FLAG (op, FLAG_APPLIED))
  642.        break;
  643.      if(op==NULL) break;
  644.      s = query_name(op);
  645. #if 1                         /* Hack to remove (readied) from a bow description */
  646.      if (strcmp (s + strlen (s) - 10, " (readied)") == 0)
  647.        s[strlen (s) - 10] = 0;
  648. #endif
  649.      sprintf (obuf, "Range: %s (%s)", s, 
  650.             op && op->race ? op->race : "nothing");
  651.    }
  652.     break;
  653.    case range_magic:
  654. #ifdef CASTING_TIME
  655.     if (pl->casting > -1) {
  656.       if (pl->casting == 0)
  657.       sprintf(obuf,"Range: Holding spell (%s)",
  658.               pl->spell->name);
  659.       else
  660.       sprintf(obuf,"Range: Casting spell (%s)",
  661.               pl->spell->name);
  662.     }
  663.     else
  664. #endif
  665.       sprintf(obuf,"Range: spell (%s)",
  666.               spells[pl->contr->chosen_spell].name);
  667.     break;
  668.    case range_wand:
  669.     sprintf(obuf,"Range: wand (%s)",
  670.           pl->contr->known_spell ?
  671.           spells[pl->contr->chosen_item_spell].name : "unknown");
  672.     break;
  673.    case range_rod:
  674.     sprintf(obuf,"Range: rod (%s)",
  675.           pl->contr->known_spell ?
  676.           spells[pl->contr->chosen_item_spell].name : "unknown");
  677.     break;
  678.    case range_horn:
  679.     sprintf(obuf,"Range: horn (%s)",
  680.           pl->contr->known_spell ?
  681.           spells[pl->contr->chosen_item_spell].name : "unknown");
  682.     break;
  683.     /* range_scroll is only used for controlling golems.  If the
  684.      * the player does not have a golem, reset some things.
  685.      */
  686.    case range_scroll:
  687.     if (pl->contr->golem!=NULL)
  688.       sprintf(obuf,"Range: golem (%s)",pl->contr->golem->name);
  689.     else {
  690.       pl->contr->shoottype = range_none;
  691.       strcpy(obuf,"Range: nothing");
  692.     }
  693.     break;
  694.    case range_skill:
  695.        sprintf(obuf,"Skill: %s", pl->chosen_skill!=NULL ?
  696.         skills[pl->chosen_skill->stats.sp].name : "none");
  697.     break;
  698.    default:
  699.     strcpy(obuf,"Range: illegal");
  700.   }
  701.   pl->contr->last_known_spell = pl->contr->known_spell;
  702.   pl->contr->last_shoot=pl->contr->shoottype;
  703.   pl->contr->last_spell=chosen_spell;
  704. }
  705.  
  706. void set_title(object *pl,char *buf)
  707. {
  708.   if(pl->contr->last_value==-1) {
  709.     /* Eneq(@csd.uu.se): Let players define their own titles. */
  710.  
  711.     if (pl->contr->own_title[0]=='\0')
  712.       sprintf(buf,"Player: %s the %s",pl->name,pl->contr->title);
  713.     else
  714.       sprintf(buf,"Player: %s the %s",pl->name,pl->contr->own_title);
  715.   }
  716. }
  717.  
  718.  
  719.  
  720. void draw_stats(object *pl) {
  721.   char buff[7][MAX_BUF];
  722.   int flag[7];
  723.   int i, chosen_spell;
  724.  
  725.   if(pl->type!=PLAYER) {
  726.     LOG(llevError,"Warning: draw_stats() in non-player: %s (%d)\n",
  727.             pl->name,pl->count);
  728.     return;
  729.   }
  730.  
  731.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  732.     esrv_update_stats(pl->contr->eric_server,pl);
  733.     return;
  734.   }
  735.  
  736.   for(i=0;i<7;i++)
  737.     flag[i]=0;
  738.  
  739.   if(pl->contr->last_value==-1) {
  740.     flag[0]=1;
  741.     set_title(pl,buff[0]);
  742.   }
  743.   if(pl->contr->last_value==-1||pl->stats.exp!=pl->contr->last_stats.exp||
  744.      pl->contr->last_level!=pl->level) {
  745.     sprintf(buff[1],"Score: %5d  Level: %d",pl->stats.exp,pl->level);
  746.     flag[1]=1;
  747.     pl->contr->last_stats.exp=pl->stats.exp;
  748.     pl->contr->last_level=pl->level;
  749.   }
  750.   if(pl->contr->last_value==-1||
  751.      pl->stats.hp!=pl->contr->last_stats.hp||
  752.      pl->stats.maxhp!=pl->contr->last_stats.maxhp||
  753.      pl->stats.sp!=pl->contr->last_stats.sp||
  754.      pl->stats.maxsp!=pl->contr->last_stats.maxsp||
  755.       pl->stats.grace!=pl->contr->last_stats.grace||
  756.       pl->stats.maxgrace!=pl->contr->last_stats.maxgrace) {
  757.     sprintf(buff[2],"Hp:%d/%d Sp:%d/%d Gr:%d/%d",
  758.             pl->stats.hp,pl->stats.maxhp,pl->stats.sp,pl->stats.maxsp,
  759.                 pl->stats.grace,pl->stats.maxgrace);
  760.     flag[2]=1;
  761.     pl->contr->last_stats.hp=pl->stats.hp;
  762.     pl->contr->last_stats.maxhp=pl->stats.maxhp;
  763.     pl->contr->last_stats.sp=pl->stats.sp;
  764.     pl->contr->last_stats.maxsp=pl->stats.maxsp;
  765.      pl->contr->last_stats.grace=pl->stats.grace;
  766.      pl->contr->last_stats.maxgrace=pl->stats.maxgrace;
  767.   }
  768.   if(pl->contr->last_value==-1||
  769.     pl->stats.Dex!=pl->contr->last_stats.Dex ||
  770.     pl->stats.Con!=pl->contr->last_stats.Con ||
  771.     pl->stats.Str!=pl->contr->last_stats.Str ||
  772.     pl->stats.Int!=pl->contr->last_stats.Int ||
  773.     pl->stats.Wis!=pl->contr->last_stats.Wis ||
  774.     pl->stats.Pow!=pl->contr->last_stats.Pow ||
  775.     pl->stats.Cha!=pl->contr->last_stats.Cha) {
  776.     sprintf(buff[3],"S%2d D%2d Co%2d I%2d W%2d P%2d Ch%2d",
  777.             pl->stats.Str,pl->stats.Dex,pl->stats.Con,
  778.             pl->stats.Int,pl->stats.Wis,pl->stats.Pow,
  779.         pl->stats.Cha);
  780.     flag[3]=1;
  781.     pl->contr->last_stats.Str=pl->stats.Str;
  782.     pl->contr->last_stats.Con=pl->stats.Con;
  783.     pl->contr->last_stats.Dex=pl->stats.Dex;
  784.     pl->contr->last_stats.Int=pl->stats.Int;
  785.     pl->contr->last_stats.Wis=pl->stats.Wis;
  786.     pl->contr->last_stats.Pow=pl->stats.Pow;
  787.     pl->contr->last_stats.Cha=pl->stats.Cha;
  788.   }
  789.   if(pl->contr->last_value==-1||
  790.      pl->stats.wc!=pl->contr->last_stats.wc||
  791.      pl->stats.ac!=pl->contr->last_stats.ac||
  792.      pl->armour!=pl->contr->last_armour||
  793.      pl->stats.dam!=pl->contr->last_stats.dam) {
  794.      sprintf(buff[4],"Wc:%3d Dam:%3d Ac:%3d Arm:%3d",
  795.              pl->stats.wc,pl->stats.dam,pl->stats.ac,pl->armour);
  796.      flag[4]=1;
  797.      pl->contr->last_stats.wc=pl->stats.wc;
  798.      pl->contr->last_stats.ac=pl->stats.ac;
  799.      pl->contr->last_stats.dam=pl->stats.dam;
  800.      pl->contr->last_armour=pl->armour;
  801.    }
  802.   if(pl->contr->last_value==-1||pl->contr->last_speed!=pl->speed||
  803.      pl->stats.food!=pl->contr->last_stats.food||
  804.      pl->contr->last_weapon_sp!=pl->contr->weapon_sp) {
  805.      flag[5]=1;
  806.      if(pl->stats.food<100&&(pl->stats.food&4))
  807.        sprintf(buff[5],"Speed: %3.2f (%1.2f) Food: *%d* HUNGRY!",
  808.                pl->speed,pl->speed/pl->contr->weapon_sp,pl->stats.food);
  809.      else
  810.        sprintf(buff[5],"Speed: %3.2f (%1.2f)  Food: %3d",
  811.                pl->speed,pl->speed/pl->contr->weapon_sp,pl->stats.food);
  812.      pl->contr->last_stats.food=pl->stats.food;
  813.      pl->contr->last_speed=pl->speed;
  814.      pl->contr->last_weapon_sp=pl->contr->weapon_sp;
  815.   }
  816.   chosen_spell = (pl->contr->shoottype==range_magic)? pl->contr->chosen_spell :
  817.     pl->contr->chosen_item_spell;
  818. #ifdef CASTING_TIME
  819.   if(pl->spell_state||pl->contr->last_value==-1||
  820.     pl->contr->last_shoot!=pl->contr->shoottype||
  821.      ((pl->contr->shoottype>range_bow && pl->contr->shoottype < range_size)&&
  822.        pl->contr->last_spell!=chosen_spell)) {
  823.     pl->spell_state = 0;
  824. #else
  825.   if(pl->contr->last_value==-1||pl->contr->last_shoot!=pl->contr->shoottype||
  826.      ((pl->contr->shoottype>range_bow && pl->contr->shoottype < range_size)&&
  827.        pl->contr->last_spell!=chosen_spell)) {
  828. #endif
  829.     flag[6]=1;
  830.      rangetostring(pl,buff[6]);
  831.   }
  832.  
  833.   if(pl->contr->shoottype==range_skill) {
  834.     flag[6]=1;
  835.      rangetostring(pl,buff[6]);
  836.   }
  837.  
  838.   for(i=0;i<7;i++)
  839.     if(flag[i]) {
  840.       strcat(buff[i],"                     "); /* In case it became shorter */
  841.       XDrawImageString(pl->contr->gdisp,pl->contr->win_stats,
  842.         pl->contr->gc_stats,10,i*14+10, buff[i],strlen(buff[i]));
  843.     }
  844.   if(pl->contr->last_value!= -1)
  845.     draw_message_window(pl); /* Update bars */
  846.   pl->contr->last_value=pl->value;
  847. }
  848.  
  849. void draw_all_info(object *pl) {
  850.   int i;
  851.  
  852.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  853.     esrv_foo(pl->contr->eric_server,"draw_all_info");
  854.     return;
  855.   }
  856.  
  857.   XClearWindow(pl->contr->gdisp,pl->contr->win_info);
  858.   if ((pl->contr->scroll) && (pl->contr->infofull)) {
  859.      int j;
  860.      for (i=0; i<pl->contr->infolines; i++) {
  861.     j = (pl->contr->infopos+i + 1) % pl->contr->infolines;
  862.         XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
  863.          pl->contr->gc_info,FONTWIDTH,(i+1)*FONTHEIGHT,
  864.          pl->contr->info[j],  strlen(pl->contr->info[j]));
  865.      }
  866.   }
  867.   else 
  868.       for(i=0;i<pl->contr->infolines;i++)
  869.         XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
  870.          pl->contr->gc_info,FONTWIDTH,(i+1)*FONTHEIGHT,
  871.          pl->contr->info[i],strlen(pl->contr->info[i]));
  872. }
  873.  
  874. #define draw_inv_face(pl,win,gc,x,y,face) \
  875. { \
  876.   if (pl->color_pixmaps) \
  877.   { \
  878.     XSetClipMask(pl->gdisp, gc, pl->masks[(face)]); \
  879.     XSetClipOrigin(pl->gdisp, gc, x, (y) - 24); \
  880.     XCopyArea(pl->gdisp, pl->pixmaps[(face)], win, gc, 0, 0, 24, 24, \
  881.         (unsigned int) (x), (unsigned int) ((y) - 24)); \
  882.   } \
  883.   else if(pl->use_pixmaps) \
  884.   { \
  885.     XSetClipMask(pl->gdisp, gc, pl->pixmaps[(face)]); \
  886.     XSetClipOrigin(pl->gdisp, gc, x, (y) - 24); \
  887.     XCopyPlane(pl->gdisp,pl->pixmaps[(face)],win,gc,0,0,24,24, \
  888.                (unsigned int) (x),(unsigned int) ((y) - 24),1); \
  889.   } \
  890.   else \
  891.   { \
  892.     XChar buf; \
  893.     buf = FontindexToXChar((Fontindex) (face)); \
  894.     XDrawString16(pl->gdisp,win,gc,x,y,&buf,1); \
  895.   } \
  896. }
  897.  
  898.  
  899. /* This routine has gotten a little more complicated with the addition
  900.  * of color pixmaps (XPM).  This is because normally, drawing a face
  901.  * would overwrite the old face drawn there.  However, with shape masks,
  902.  * this does not happen.  So in order to keep things looking right, a
  903.  * XClearArea is called to clear the face area before draw_face is
  904.  * called.  This is only done if the user is using color pixmaps.
  905.  * Mark Wedel (master@rahul.net)
  906.  */
  907. /* Also, I changed the start height values to start at 16 + 24*(other stuff)
  908.  * This is because the draw_face calls start at 40 + 24*(other_stuff).
  909.  * The draw_face macro then subtracts 24.  40-24 = 16.  Without this
  910.  * changed, not all information was being erased (This is because of
  911.  * the change to use XClearArea instead of overdrawing the area with
  912.  * another face.  The later case did not look nice when the color
  913.  * pixmap (XPM) additions.  MSW (master@rahul.net)
  914.  */
  915. void draw_inventory(object *pl) {
  916.   signed short items;
  917.   int i,j;
  918.   object *tmp;
  919.   char buf[MAX_BUF], *obj_name, name_buf[MAX_BUF];
  920.   player *p=pl->contr;
  921.  
  922.   if(pl->type!=PLAYER)
  923.     return;
  924.   if(p->freeze_inv)
  925.     return;
  926.  
  927.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  928.       LOG(llevDebug,"Warning, draw_inventory called in eric server mode.\n");
  929. /*    esrv_foo(pl->contr->eric_server,"draw_inventory");*/
  930.     return;
  931.   }
  932.  
  933.   for(tmp=pl->inv,items=0;tmp!=NULL;tmp=tmp->below)
  934.     if (show_what_object(tmp,p->show_what))
  935.       items++;
  936.  
  937.   if(p->scroll_inv>(items - p->inv_size))
  938.     p->scroll_inv=items-p->inv_size;
  939.   if(p->scroll_inv<0)
  940.     p->scroll_inv=0;
  941.   if(p->last_weight!=pl->weight+pl->carrying) {
  942.     p->last_weight=pl->weight+pl->carrying;
  943.     sprintf(buf,"Inventory%s: (%s)",
  944.             (p->show_what == show_applied ? " (applied) " :
  945.             (p->show_what == show_unapplied ? " (unapplied) " : 
  946.         (p->show_what == show_unpaid ? " (unpaid) " :
  947.         (p->show_what == show_cursed ? " (cursed) ": 
  948.         (p->show_what == show_magical ? " (magical) " :
  949.         (p->show_what == show_nonmagical ? " (nonmagical) " : "")))))),
  950.             query_weight(pl));
  951.     XDrawImageString(p->gdisp,p->win_inv,
  952.                      p->gc_inv_text,8,13,buf,strlen(buf));
  953.   }
  954.   for(tmp=pl->inv,i=0;tmp!=NULL;tmp=tmp->below,i++) {
  955.     if (!show_what_object(tmp, p->show_what))
  956.     {
  957.       i--;
  958.       continue;
  959.     }
  960.     if(i-p->scroll_inv>=p->inv_size||i<p->scroll_inv)
  961.       continue;
  962.  
  963.     if(p->inv_face[i-p->scroll_inv]!=tmp->face->number) {
  964.       p->inv_face[i-p->scroll_inv]=tmp->face->number;
  965.       if (p->color_pixmaps) 
  966.     XClearArea(p->gdisp, p->win_inv, 4, 16+24*(i-p->scroll_inv), 24,24,False);
  967.       draw_face(p,p->win_inv,p->gc_inv_icon,4,40+24*(i-p->scroll_inv),tmp->face->number);
  968.     }
  969.     obj_name = query_name(tmp);
  970.  
  971.     /* Name buf is just the object name and weight.  Both need to be stored,
  972.      * otherwise this would not always be updated (when dropping a short
  973.      * sword with another below it, the weight of the next short sword would
  974.      * be shown as the same as the original.
  975.      */
  976.     strcpy(name_buf,obj_name);
  977.     strcat(name_buf,query_weight(tmp));
  978.  
  979.     if(p->inv_name[i-p->scroll_inv] &&
  980.      !strcmp(p->inv_name[i-p->scroll_inv],name_buf))
  981.       continue;
  982.     sprintf(buf,p->format_inv,obj_name,query_weight(tmp));
  983.  
  984.     if (p->show_inv_icon) {
  985.       XClearArea(p->gdisp, p->win_inv, 32, 16+24*(i-p->scroll_inv), 24,24,False);
  986.       if (QUERY_FLAG(tmp, FLAG_INV_LOCKED))
  987.     draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
  988.         inv_lock_face->number);
  989.       if (QUERY_FLAG(tmp, FLAG_KNOWN_CURSED)) {
  990.         if (QUERY_FLAG(tmp, FLAG_DAMNED)) {
  991.       draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
  992.         inv_damn_face->number);
  993.         } else {
  994.       draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
  995.           inv_curse_face->number);
  996.     }
  997.       }
  998.       if (QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL) &&
  999.        !QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_BEEN_APPLIED))
  1000.       draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
  1001.         inv_magic_face->number);
  1002.       if (QUERY_FLAG(tmp, FLAG_APPLIED))
  1003.     draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
  1004.         inv_equip_face->number);
  1005.       if (QUERY_FLAG(tmp, FLAG_UNPAID))
  1006.     draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
  1007.         inv_unpaid_face->number);
  1008.     } /* if show_inv_icon */
  1009.  
  1010.     if (p->inv_name[i-p->scroll_inv])
  1011.     free_string(p->inv_name[i-p->scroll_inv]);
  1012.     p->inv_name[i-p->scroll_inv] = add_string(name_buf);
  1013.  
  1014.     if (p->show_inv_icon)
  1015.     XDrawImageString(p->gdisp,p->win_inv,
  1016.                      p->gc_inv_text,60,34+24*(i-p->scroll_inv)
  1017.                      ,buf,strlen(buf));
  1018.     else
  1019.     XDrawImageString(p->gdisp,p->win_inv,
  1020.                      p->gc_inv_text,32,34+24*(i-p->scroll_inv)
  1021.                      ,buf,strlen(buf));
  1022.   }
  1023.   if((i-p->scroll_inv)<=p->nrofdrawn_inv) {
  1024.     int start_height=16+24*(i-p->scroll_inv);
  1025.     int height;
  1026.     for(j=i;(j-p->scroll_inv)<=p->nrofdrawn_inv&&
  1027.         (j-p->scroll_inv)<p->inv_size;j++) {
  1028.       p->inv_face[j-p->scroll_inv]=blank_face->number;
  1029.       p->inv_name[j-p->scroll_inv]=NULL;
  1030.     }
  1031.     if(p->inv_size<p->nrofdrawn_inv)
  1032.       height=p->inv_size*24;
  1033.     else
  1034.       height=p->nrofdrawn_inv*24;
  1035.     XClearArea(p->gdisp,p->win_inv,0,start_height,
  1036.                p->invhint.width-23,height*24,0);
  1037.   }
  1038.   if(i<p->inv_size)
  1039.     i=p->inv_size;
  1040.   p->nrofdrawn_inv=i;
  1041.   j =((int)p->inv_size * (int)p->barlength_inv / i);
  1042.   if(p->scrollsize_inv!=j||
  1043.      p->last_scroll_inv!=p->scroll_inv)
  1044.   { /* Change the scrollbar if different */
  1045.     int offset = (int)p->scroll_inv * (int)p->barlength_inv / i;
  1046.     XClearArea(p->gdisp,p->win_inv,p->invhint.width-20,17+p->scrollstart_inv,
  1047.                16,p->scrollsize_inv,0);
  1048.     p->scrollsize_inv=j;
  1049.     p->scrollstart_inv=offset;
  1050.     p->last_scroll_inv=p->scroll_inv;
  1051.     XFillRectangle(p->gdisp,p->win_inv,p->gc_inv_text,
  1052.                    p->invhint.width-20,17+offset,16,p->scrollsize_inv);
  1053.   }
  1054. }
  1055.  
  1056. void draw_inventory_faces(object *pl) {
  1057.   int i,items;
  1058.   object *tmp, *inv=pl->inv;
  1059.   player *p=pl->contr;
  1060.  
  1061.   if(p->freeze_inv)
  1062.     return;
  1063.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1064. /* This gets to be a bit too verbose */
  1065. /*      LOG(llevDebug,"Warning, draw_inventory_faces has no effect.\n");*/
  1066. /*    esrv_foo(pl->contr->eric_server,"draw_inventory_faces");*/
  1067.     return;
  1068.   }
  1069.  
  1070.   for(tmp=inv,items=0;tmp!=NULL;tmp=tmp->below)
  1071.     if (show_what_object(tmp, p->show_what))
  1072.       items++;
  1073.   if(p->scroll_inv>items-p->inv_size)
  1074.     p->scroll_inv=items-p->inv_size;
  1075.   if(p->scroll_inv<0)
  1076.     p->scroll_inv=0;
  1077.   for(tmp=inv,i=0;tmp!=NULL;tmp=tmp->below) {
  1078.     if (show_what_object(tmp, p->show_what)) {
  1079.     if (!(i-p->scroll_inv>=p->inv_size || i<p->scroll_inv ||
  1080.       p->inv_face[i-p->scroll_inv]==tmp->face->number)) {
  1081.  
  1082.         p->inv_face[i-p->scroll_inv]=tmp->face->number;
  1083.         if (p->color_pixmaps) 
  1084.         XClearArea(p->gdisp, p->win_inv, 4, 16+24*(i-p->scroll_inv), 24,24,False);
  1085.         draw_face(p,p->win_inv,p->gc_inv_icon,4,40+24*(i-p->scroll_inv),tmp->face->number);
  1086.     }
  1087.     i++;
  1088.     }
  1089.   }
  1090.   if((i-p->scroll_inv)<=p->nrofdrawn_inv) {
  1091.     int    start_height = 16 + 24*(i-p->scroll_inv),height;
  1092.     if (p->inv_size<p->nrofdrawn_inv)
  1093.         height = p->inv_size * 24;
  1094.     else
  1095.         height = p->nrofdrawn_inv * 24;
  1096.     XClearArea(p->gdisp, p->win_inv, 0, start_height, 28, height, False);
  1097.  
  1098.   }
  1099. }
  1100.  
  1101. void draw_all_inventory(object *pl) {
  1102.   int i;
  1103.   player *p=pl->contr;
  1104.  
  1105.   for(i=0;i<p->inv_size;i++) {
  1106.     p->inv_face[i]=blank_face->number;
  1107.     p->inv_name[i]=NULL;
  1108.   }
  1109.  
  1110.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1111.      LOG(llevDebug, "Warning, draw_all_inventory called in eric server mode\n");
  1112. /*  esrv_foo(pl->contr->eric_server,"draw_all_inventory");*/
  1113.     return;
  1114.   }
  1115.  
  1116.   XClearWindow(p->gdisp,p->win_inv);
  1117.   XDrawRectangle(p->gdisp,p->win_inv,
  1118.                  p->gc_inv_text,p->invhint.width-22,15,20,p->barlength_inv+4);
  1119.   p->scrollsize_inv=1,p->scrollstart_inv=1,
  1120.   p->nrofdrawn_inv=0;
  1121.   p->last_weight= (-1);
  1122.   p->freeze_inv=0;
  1123.   draw_inventory(pl);
  1124. }
  1125.  
  1126.  
  1127. void draw_look(object *pl) {
  1128.   signed short i,j,items;
  1129.   object *tmp,*top;
  1130.   char buf[MAX_BUF];
  1131.   player *p=pl->contr;
  1132.  
  1133.   if(p->freeze_look)
  1134.     return;
  1135.  
  1136.   if(QUERY_FLAG(pl, FLAG_REMOVED) || pl->map == NULL || pl->map->in_memory != MAP_IN_MEMORY)
  1137.     return;
  1138.   if(out_of_map(pl->map,pl->x,pl->y))
  1139.     return;
  1140.  
  1141.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1142.     esrv_draw_look(pl);
  1143.     return;
  1144.   }
  1145.  
  1146.  
  1147.   /* Eneq(@csd.uu.se): Display container or look. */
  1148.  
  1149.   if (pl->container==NULL)
  1150.     for(top=get_map_ob(pl->map,pl->x,pl->y);top!=NULL&&top->above!=NULL;
  1151.         top=top->above);
  1152.   else
  1153.     top = pl->container->inv;
  1154.   for(tmp=top,items=0;(tmp!=NULL)&&(!(tmp->above&&QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR));tmp=tmp->below)
  1155.     if LOOK_OBJ(tmp)
  1156.       items++;
  1157.  
  1158.   if(p->scroll_look>items-p->look_size)
  1159.     p->scroll_look=items-p->look_size;
  1160.   if(p->scroll_look<0)
  1161.     p->scroll_look=0;
  1162.   XSetForeground(p->gdisp,p->gc_look_text,
  1163.                  p->gforeground);
  1164.  
  1165.   for(tmp=top,i=0;(tmp!=NULL)&&(!(tmp->above&&QUERY_FLAG(tmp->above,
  1166.     FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR));tmp=tmp->below,i++)
  1167.   {
  1168.     if (!LOOK_OBJ(tmp)) {
  1169.       i--;
  1170.       continue;
  1171.     }
  1172.     /* If we have drawn all that is possible, break out of this loop */
  1173.     if ( i- p->scroll_look>=p->look_size) break;
  1174.     if (i<p->scroll_look)
  1175.       continue;
  1176.  
  1177.     if(p->look_face[i-p->scroll_look]!=tmp->face->number) {
  1178.     p->look_face[i-p->scroll_look]=tmp->face->number;
  1179.     if (p->color_pixmaps) 
  1180.         XClearArea(p->gdisp, p->win_look, 4, 16+24*(i-p->scroll_look), 24,24,False);
  1181.     draw_face(p,p->win_look,p->gc_look_icon,4,40+24*(i-p->scroll_look),tmp->face->number);
  1182.     }
  1183.     if(QUERY_FLAG(tmp, FLAG_NO_PICK)) {
  1184.       char *cp;
  1185.       strncpy(buf,query_name(tmp),p->look_chars); /* Don't worry about screenwidth */
  1186.       buf[p->look_chars]='\0';
  1187.       cp=strchr(buf,'\0');
  1188.  
  1189.       /* We need to pad the string with spaces, so that it overwrites the
  1190.        * previous item name printed in the window.
  1191.        */
  1192.  
  1193.       if((sint16)strlen(buf)<p->look_chars)
  1194.         memset((void *)cp,' ',p->look_chars-strlen(buf));
  1195.       buf[p->look_chars]='\0';
  1196.     } else
  1197.       sprintf(buf,p->format_look,query_name(tmp),query_weight(tmp));
  1198.     if(!p->look_name[i-p->scroll_look] || strcmp(buf,p->look_name[i-p->scroll_look])) {
  1199.     if (p->look_name[i-p->scroll_look])
  1200.         free_string(p->look_name[i-p->scroll_look]);
  1201.     p->look_name[i-p->scroll_look] = add_string(buf);
  1202.     XDrawImageString(p->gdisp,p->win_look,
  1203.                      p->gc_look_text,32,34+24*(i-p->scroll_look)
  1204.                      ,buf,strlen(buf));
  1205.     }
  1206.   }
  1207.  
  1208.   /* If there are not enough items to fill in the display area,
  1209.    * then set the unused ares to nothing.
  1210.    */
  1211.  
  1212.   if(items<p->nrofdrawn_look) {
  1213.     int start_height=16+24*(i-p->scroll_look);
  1214.     int height;
  1215.  
  1216.     for(j=i;(j-p->scroll_look)<=p->nrofdrawn_look&&
  1217.         (j-p->scroll_look)<p->look_size;j++) {
  1218.       p->look_name[j-p->scroll_look]=NULL;
  1219.       p->look_face[j-p->scroll_look]=blank_face->number;
  1220.     }
  1221.     if(p->look_size<p->nrofdrawn_look)
  1222.       height=p->look_size*24;
  1223.     else
  1224.       height=p->nrofdrawn_look*24;
  1225.     XClearArea(p->gdisp,p->win_look,0,start_height,
  1226.                p->lookhint.width-23,height,0);
  1227.   }
  1228.   p->nrofdrawn_look=items;
  1229.   if(items<p->look_size)
  1230.     items=p->look_size;
  1231.   j =((int)p->look_size * (int)p->barlength_look / items);
  1232.  
  1233.   /* draw the scrollbar now */
  1234.   if(p->scrollsize_look!=(unsigned short) j||
  1235.      p->last_scroll_look!=p->scroll_look) {
  1236.     int offset =(int)p->scroll_look * (int)p->barlength_look / items;
  1237.  
  1238.     XClearArea(p->gdisp,p->win_look,p->lookhint.width-20,
  1239.                17+p->scrollstart_look,16,p->scrollsize_look,0);
  1240.     p->scrollsize_look=j;
  1241.     p->scrollstart_look=offset;
  1242.     p->last_scroll_look=p->scroll_look;
  1243.     XFillRectangle(p->gdisp,p->win_look,p->gc_look_text,
  1244.                    p->lookhint.width-20,17+offset,16,p->scrollsize_look);
  1245.   }
  1246. }
  1247.  
  1248. /* This only draws the look faces.  Maybe used for animations?
  1249.  */
  1250.  
  1251. void draw_look_faces(object *pl) {
  1252.   int i,items;
  1253.   object *tmp,*top;
  1254.   player *p=pl->contr;
  1255.  
  1256.  
  1257.   if(p->freeze_look)
  1258.     return;
  1259.   if(QUERY_FLAG(pl, FLAG_REMOVED)||out_of_map(pl->map,pl->x,pl->y))
  1260.     return;
  1261.  
  1262.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1263.     esrv_foo(pl->contr->eric_server,"draw_look_faces");
  1264.     return;
  1265.   }
  1266.   for(top=(pl->container?pl->container->inv:get_map_ob(pl->map,pl->x,pl->y));
  1267.       top!=NULL&&top->above!=NULL;
  1268.       top=top->above);
  1269.  
  1270.   for(tmp=top,items=0;(tmp!=NULL)&&(!(tmp->above&&
  1271.     QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR)); tmp=tmp->below)
  1272.     if LOOK_OBJ(tmp)
  1273.       items++;
  1274.  
  1275.   /* If the number of objects is different than what was drawn
  1276.    * before, then we should also draw the names.  So just call
  1277.    * draw_look to do it.
  1278.    */
  1279.   if (p->nrofdrawn_look!=items) {
  1280.     draw_look(pl);
  1281.     return;
  1282.   }
  1283.  
  1284.   if(p->scroll_look>items-p->look_size)
  1285.     p->scroll_look=items-p->look_size;
  1286.   if(p->scroll_look<0)
  1287.     p->scroll_look=0;
  1288.  
  1289.   for(tmp=top,i=0;(tmp!=NULL)&&(!(tmp->above&&QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR));tmp=tmp->below,i++) {
  1290.     if (!LOOK_OBJ(tmp)) {
  1291.       i--;
  1292.       continue;
  1293.     }
  1294.     if(i-p->scroll_look>=p->look_size) break;
  1295.     if (i<p->scroll_look) continue;
  1296.  
  1297.     if(p->look_face[i-p->scroll_look]!=tmp->face->number) {
  1298.     p->look_face[i-p->scroll_look]=tmp->face->number;
  1299.     if (p->color_pixmaps) 
  1300.         XClearArea(p->gdisp, p->win_look, 4, 16+24*(i-p->scroll_look), 24,24,False);
  1301.     draw_face(p,p->win_look,p->gc_look_icon,4,40+24*(i-p->scroll_look),tmp->face->number);
  1302.     }
  1303.   }
  1304.   /* No need to do any erasing, because if the number of objects has
  1305.    * decreased, the draw_look function was called instead.
  1306.    */
  1307. }
  1308.  
  1309. void draw_all_look(object *pl) {
  1310.   int i;
  1311.   player *p=pl->contr;
  1312.  
  1313.   for(i=0;i<p->look_size;i++) {
  1314.     p->look_face[i]=blank_face->number;
  1315.     p->look_name[i]=NULL;
  1316.   }
  1317.  
  1318.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1319.     esrv_draw_look(pl);
  1320.     return;
  1321.   }
  1322.  
  1323.   XClearWindow(p->gdisp,p->win_look);
  1324.   XDrawRectangle(p->gdisp,p->win_look,p->gc_look_text,
  1325.                  p->lookhint.width-22,15,20,p->barlength_look+4);
  1326.   p->scrollsize_look=1,p->scrollstart_look=1,
  1327.   p->nrofdrawn_look=0;
  1328.   if (!pl->container)
  1329.   XDrawImageString(p->gdisp,p->win_look,
  1330.                      p->gc_look_text,8,13,"You see:     ",13);
  1331.   else
  1332.     XDrawImageString(p->gdisp,p->win_look,
  1333.                      p->gc_look_text,8,13,"In container:",13);
  1334.   p->freeze_look=0;
  1335.   draw_look(pl);
  1336. }
  1337.  
  1338. #define MAX_BARS_MESSAGE 80
  1339.  
  1340. static void draw_stat_bar(object *pl, int bar_pos, 
  1341.               int height, int old_height,
  1342.               int is_alert, int old_is_alert)
  1343. {
  1344.   if(height==old_height && is_alert==old_is_alert) /* nothing changed */
  1345.     return;
  1346.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1347.     esrv_foo(pl->contr->eric_server,"draw_stat_bar");
  1348.     return;
  1349.   }
  1350.  
  1351.   if(height!=MAX_BARS_MESSAGE)    /* clear the top of the bar */
  1352.     XClearArea(pl->contr->gdisp,pl->contr->win_message,
  1353.            bar_pos, 4,
  1354.            10, MAX_BARS_MESSAGE-height,
  1355.            0);
  1356.   if(height==0)            /* empty bar */
  1357.     return;
  1358.   if(is_alert && pl->contr->iscolor) /* this should have its own gc */
  1359.      XSetForeground(pl->contr->gdisp,pl->contr->gc_look_text,
  1360.             pl->contr->discolor[3].pixel);
  1361.        XFillRectangle(pl->contr->gdisp,pl->contr->win_message,
  1362.          pl->contr->gc_look_text,
  1363.          bar_pos, 4+MAX_BARS_MESSAGE-height,
  1364.          10, height);
  1365.   if(is_alert && pl->contr->iscolor)
  1366.      XSetForeground(pl->contr->gdisp,pl->contr->gc_look_text,
  1367.             pl->contr->gforeground);
  1368.      }
  1369.  
  1370. void draw_message_window(object *pl) {
  1371.   int bar,is_alert;
  1372.  
  1373.   /* draw hp bar */
  1374.   if(pl->stats.maxhp>0)
  1375.     {
  1376.       bar=(pl->stats.hp*MAX_BARS_MESSAGE)/pl->stats.maxhp;
  1377.       if(bar<0)
  1378.     bar=0;
  1379.       is_alert=(pl->stats.hp <= pl->stats.maxhp/4);
  1380.     }
  1381.   else
  1382.     {
  1383.       bar=0;
  1384.       is_alert=0;
  1385.     }
  1386.   draw_stat_bar(pl,20,
  1387.         bar,pl->contr->scrollsize_hp,
  1388.         is_alert,pl->contr->scrollhp_alert);
  1389.   pl->contr->scrollsize_hp=bar;
  1390.   pl->contr->scrollhp_alert=is_alert;
  1391.  
  1392.   /* draw sp bar.  spellpoints can go above max
  1393.    * spellpoints via supercharging with the transferrance spell,
  1394.    * or taking off items that raise max spellpoints.
  1395.    */
  1396.   if (pl->stats.sp>pl->stats.maxsp)
  1397.     bar = MAX_BARS_MESSAGE;
  1398.   else
  1399.     bar=(pl->stats.sp*MAX_BARS_MESSAGE)/pl->stats.maxsp;
  1400.   if(bar<0) 
  1401.     bar=0;
  1402.  
  1403.   is_alert=(pl->stats.sp <= pl->stats.maxsp/4);
  1404.  
  1405.   draw_stat_bar(pl,60,
  1406.         bar,pl->contr->scrollsize_sp,
  1407.         is_alert,pl->contr->scrollsp_alert);
  1408.        pl->contr->scrollsize_sp=bar;
  1409.   pl->contr->scrollsp_alert=is_alert;
  1410.   
  1411.   /* draw grace bar.  grace can go above  max or below min
  1412.    */
  1413.   if (pl->stats.grace>pl->stats.maxgrace)
  1414.     bar = MAX_BARS_MESSAGE;
  1415.   else
  1416.     bar=(pl->stats.grace*MAX_BARS_MESSAGE)/pl->stats.maxgrace;
  1417.   if(bar<0) 
  1418.     bar=0;
  1419.  
  1420.   is_alert=(pl->stats.grace <= pl->stats.maxgrace/4);
  1421.  
  1422.   draw_stat_bar(pl,100,
  1423.         bar,pl->contr->scrollsize_grace,
  1424.         is_alert,pl->contr->scrollgrace_alert);
  1425.        pl->contr->scrollsize_grace=bar;
  1426.   pl->contr->scrollgrace_alert=is_alert;
  1427.   
  1428.   /* draw food bar */
  1429.   bar=(pl->stats.food*MAX_BARS_MESSAGE)/999;
  1430.   if(bar<0) 
  1431.     bar=0;
  1432.   is_alert=(pl->stats.food <= 999/4);
  1433.   draw_stat_bar(pl,140,
  1434.         bar,pl->contr->scrollsize_food,
  1435.         is_alert,pl->contr->scrollfood_alert);
  1436.        pl->contr->scrollsize_food=bar;
  1437.   pl->contr->scrollfood_alert=is_alert;
  1438. }
  1439.  
  1440. void xwritedown(object *pl,char *txt,int x) {
  1441.   int y=13;
  1442.  
  1443.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1444.     esrv_foo(pl->contr->eric_server,"xwritedown");
  1445.     return;
  1446.   }
  1447.  
  1448.   for(;*txt!='\0';txt++,y+=13)
  1449.     XDrawImageString(pl->contr->gdisp,pl->contr->win_message,
  1450.                      pl->contr->gc_look_text,x,y,txt,1);
  1451. }
  1452.  
  1453. void draw_all_message(object *pl) {
  1454.  
  1455.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1456.     LOG(llevDebug,"draw_all_message called in eric_server mode");
  1457.     return;
  1458.   }
  1459.  
  1460.   XClearWindow(pl->contr->gdisp,pl->contr->win_message);
  1461.   pl->contr->scrollsize_hp=pl->contr->scrollsize_sp=
  1462.   pl->contr->scrollsize_food=pl->contr->scrollsize_grace=0;
  1463.   xwritedown(pl,"HP",06);
  1464.   XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
  1465.                  pl->contr->gc_look_text,18,2,14,MAX_BARS_MESSAGE+4);
  1466.   xwritedown(pl,"Mana",46);
  1467.   XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
  1468.                  pl->contr->gc_look_text,58,2,14,MAX_BARS_MESSAGE+4);
  1469.   xwritedown(pl,"Grace",86);
  1470.   XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
  1471.                  pl->contr->gc_look_text,98,2,14,MAX_BARS_MESSAGE+4);
  1472.   xwritedown(pl,"Food",126);
  1473.   XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
  1474.                  pl->contr->gc_look_text,138,2,14,MAX_BARS_MESSAGE+4);
  1475. #ifdef USE_BUTTONS
  1476.   {
  1477.     int i;
  1478.     for (i=0;i<NUMDIRBUTTS;i++) {
  1479.       XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
  1480.                      pl->contr->gc_look_text,dirX[i],dirY[i],
  1481.                      dirW,18);
  1482.       XDrawImageString(pl->contr->gdisp,pl->contr->win_message,
  1483.                        pl->contr->gc_look_text,dirX[i]+2,dirY[i]+14,
  1484.                        dirnames[i],2);
  1485.     }
  1486.     for (i=0;i<NUMOPBUTTS;i++) {
  1487.       XDrawImageString(pl->contr->gdisp,pl->contr->win_message,
  1488.                        pl->contr->gc_look_text,opX[i]+2,opY[i]+14,
  1489.                        opnames[i],8);
  1490.       XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
  1491.                      pl->contr->gc_look_text,opX[i],opY[i],
  1492.                      48,18);
  1493.     }
  1494.   } 
  1495. #endif
  1496.   draw_message_window(pl);
  1497. }
  1498.  
  1499.  
  1500. /****************************************************************************
  1501.  * Following group is a set of functions that deal with display information
  1502.  * to the player/screen.
  1503.  *
  1504.  * Cleaned up so that only a few functions are actually needed - just
  1505.  * pass different values to it.
  1506.  *
  1507.  ****************************************************************************/
  1508. static void print_message(int colr, object *pl,const char *tmp);
  1509. static void draw_info(object *pl,const char *str);
  1510.  
  1511. /* Following prints out the contents of one of the buffer structures,
  1512.  * and clears the string.
  1513.  */
  1514.  
  1515. void flush_output_element(object *pl, Output_Buf *outputs)
  1516. {
  1517.     char tbuf[MAX_BUF];
  1518.  
  1519.     if (outputs->buf==NULL) return;
  1520.     sprintf(tbuf,"%d times %s", outputs->count, outputs->buf);
  1521.     print_message(NDI_BLACK, pl, tbuf);
  1522.     free_string(outputs->buf);
  1523.     outputs->buf=NULL;
  1524.     outputs->first_update=0;    /* This way, it will be reused */
  1525. }
  1526.  
  1527. /* Following checks the various buffers in the player structure and
  1528.  * other things, and stores/prints/whatever's the data, as appropriate.
  1529.  */
  1530.  
  1531. void check_output_buffers(object *pl, char *buf)
  1532. {
  1533.     int i, oldest=0;
  1534.  
  1535.     if (pl->contr->outputs_count<2) {
  1536.     print_message(NDI_BLACK, pl, buf);
  1537.     return;
  1538.     }
  1539.     else {
  1540.     for (i=0; i<NUM_OUTPUT_BUFS; i++) {
  1541.         if (pl->contr->outputs[i].buf && 
  1542.         !strcmp(buf, pl->contr->outputs[i].buf)) break;
  1543.         else if (pl->contr->outputs[i].first_update <
  1544.         pl->contr->outputs[oldest].first_update)
  1545.             oldest=i;
  1546.     }
  1547.     /* We found a match */
  1548.     if (i<NUM_OUTPUT_BUFS) {
  1549.         pl->contr->outputs[i].count++;
  1550.         if (pl->contr->outputs[i].count>=pl->contr->outputs_count) {
  1551.         flush_output_element(pl, &pl->contr->outputs[i]);
  1552.         }
  1553.     }
  1554.     /* No match - flush the oldest, and put the new one in */
  1555.     else {
  1556.         flush_output_element(pl, &pl->contr->outputs[oldest]);
  1557.  
  1558.         pl->contr->outputs[oldest].first_update = pticks;
  1559.         pl->contr->outputs[oldest].count = 1;
  1560.         if (pl->contr->outputs[oldest].buf!=NULL)
  1561.         free_string(pl->contr->outputs[oldest].buf);
  1562.         pl->contr->outputs[oldest].buf = add_string(buf);
  1563.     }
  1564.     }
  1565. }
  1566.         
  1567.  
  1568. /*
  1569.  * new_draw_info:
  1570.  *
  1571.  * flags is various flags - mostly color, plus a few specials.
  1572.  *
  1573.  * pri is priority.  It is a little odd - the lower the value, the more
  1574.  * important it is.  Thus, 0 gets sent no matter what.  Otherwise, the
  1575.  * value must be less than the listening level that the player has set.
  1576.  * Unfortunately, there is no clear guideline on what each level does what.
  1577.  *
  1578.  * pl can be passed as NULL - in fact, this will be done if NDI_ALL is set
  1579.  * in the flags.
  1580.  *
  1581.  */
  1582.  
  1583.  
  1584. void new_draw_info(int flags,int pri, object *pl, const char *buf)
  1585. {
  1586.  
  1587.     if (flags & NDI_ALL) {
  1588.     player    *tmppl;
  1589.  
  1590.     for (tmppl=first_player; tmppl!=NULL; tmppl=tmppl->next)
  1591.         new_draw_info((flags & ~NDI_ALL), pri, tmppl->ob, buf);
  1592.  
  1593.     if (pri<9) info_all_sockets((char*)buf);
  1594.  
  1595.     return;
  1596.     }
  1597.     if(!pl || (pl->type==PLAYER && pl->contr==NULL)) {
  1598.     /* Write to the socket? */
  1599.     print_message(0, NULL, buf);
  1600.     return;
  1601.     }
  1602.     if (pl->type!=PLAYER) return;
  1603.     if (pri>=pl->contr->listening) return;
  1604.  
  1605.     if ((flags&NDI_COLOR_MASK)==NDI_BLACK && !(flags &NDI_UNIQUE)) {
  1606.     /* following prints stuff out, as appropriate */
  1607.     check_output_buffers(pl, (char*)buf);
  1608.     }
  1609.     else {
  1610.     print_message(flags&NDI_COLOR_MASK, pl, buf);
  1611.     }
  1612. }
  1613.  
  1614. /* This is a pretty trivial function, but it allows us to use printf style
  1615.  * formatting, so instead of the calling function having to do it, we do
  1616.  * it here.  IT may also have advantages in the future for reduction of
  1617.  * client/server bandwidth (client could keep track of various strings
  1618.  */
  1619.  
  1620. void new_draw_info_format(int flags, int pri,object *pl, char *format, ...)
  1621. {
  1622.     char buf[MAX_BUF];
  1623.  
  1624.     va_list ap;
  1625.     va_start(ap, format);
  1626.  
  1627.     vsprintf(buf, format, ap);
  1628.  
  1629.     va_end(ap);
  1630.  
  1631.     new_draw_info(flags, pri, pl, buf);
  1632. }
  1633.  
  1634. void new_info_map(int color, mapstruct *map, char *str) {
  1635.     player *pl;
  1636.  
  1637.     for(pl = first_player; pl != NULL; pl = pl->next)
  1638.     if(pl->ob != NULL && pl->ob->map == map) {
  1639.         new_draw_info(color, 0, pl->ob, str);
  1640.     }
  1641. }
  1642.  
  1643. /****************************************************************************
  1644. print_message : This routine prints out the character string in tmp on the
  1645.                 info window. If in color mode, then the text will show up in
  1646.                 a color specified by the variable colr. If Black and white
  1647.                 mode, then it prints a line of "="s before and after the
  1648.                 messsage.
  1649.  
  1650.         This has been changed around - this is now a front end to
  1651.         draw_info.  draw_info should never be called directly, except
  1652.         by this functin.  Likewise, this function should only be
  1653.         called by a few functions above (new_draw_info, 
  1654.         check_output_buffers)
  1655. ****************************************************************************/
  1656.  
  1657. static void print_message(int colr, object *pl,const char *tmp) {
  1658.  
  1659.   if(!pl || (pl->type==PLAYER && pl->contr==NULL)) {
  1660. #ifdef SERVER
  1661.     if(active_socket != (sockets *) NULL)
  1662.       draw_socket(active_socket->fd,tmp);
  1663.     else
  1664. #endif
  1665.       fprintf(logfile,"%s\n",tmp);
  1666.     return;
  1667.   }
  1668.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1669.     esrv_print_msg(pl->contr->eric_server,colr,(char*) tmp);
  1670.     return;
  1671.   }
  1672.   if(tmp == (char *) NULL) {
  1673.     tmp="[NULL]";
  1674.   }
  1675.  
  1676.   if (colr!=NDI_BLACK) {
  1677.     if (pl->contr->iscolor) {
  1678.     XSetForeground(pl->contr->gdisp,pl->contr->gc_info,
  1679.         pl->contr->discolor[colr].pixel);
  1680.     draw_info(pl,tmp);
  1681.     XSetForeground(pl->contr->gdisp,pl->contr->gc_info,
  1682.         pl->contr->discolor[0].pixel);
  1683.     }
  1684.     else {
  1685.     draw_info(pl,"==========================================");
  1686.     draw_info(pl,tmp);
  1687.     draw_info(pl,"==========================================");
  1688.     }
  1689.   }
  1690.   else
  1691.     draw_info(pl, tmp);
  1692. }
  1693.  
  1694. /* This entire function won't be needed once true client/server happens. */
  1695.  
  1696.  
  1697. static void draw_info(object *pl,const char *str) {
  1698.   static char blanks[]="                                                      ";
  1699.   char *cp;
  1700.  
  1701.   /* Following should be removed - all message handling to client should be
  1702.    * done in print_message, above
  1703.    */
  1704.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1705.     LOG(llevError,"In draw_info, new client/server function will be called\n");
  1706.     esrv_drawinfo(pl->contr->eric_server,str);
  1707.     return;
  1708.   }
  1709.  
  1710.   if((cp=strchr(str,'\n'))!=NULL) {
  1711.     char *obuf = (char *) malloc(sizeof(char) * (strlen(str) + 2)), *buf = obuf;
  1712.  
  1713.     strcpy(buf,str);
  1714.     do {
  1715.       if ((cp = strchr(buf, '\n'))) {
  1716.         *cp='\0';
  1717.         draw_info(pl,buf);
  1718.         buf = cp +1;
  1719.       } else
  1720.         draw_info(pl, buf);
  1721.     } while (cp!=NULL);
  1722.     free(obuf);
  1723.     return;
  1724.   }
  1725.   /* Lets do the word wrap for messages - MSW (master@rahul.net) */
  1726.   if ((int)strlen(str) >= (int)pl->contr->infochars) {
  1727.     int i=pl->contr->infochars-1;
  1728.  
  1729.     /* i=last space (or ')' for armor.  Wrap armor, because
  1730.     otherwise, the two sets of ()() can be about half the line */
  1731.     while ((str[--i]!=' ') && (str[i]!=')') && (i!=0)) ;
  1732.     /* if i==0, string has no space.  Just let it be truncated */
  1733.     if (i!=0) {
  1734.         char *buf = (char *)malloc(sizeof(char)*(i+2));
  1735.         int j;
  1736.  
  1737.         i++;    /* want to keep the ')'.  This also keeps
  1738.             the space, but that really doesn't matter */
  1739.         strncpy(buf, str, i);
  1740.         buf[i]='\0';
  1741.         draw_info(pl, buf);
  1742.             free(buf);
  1743.  
  1744.         for (j=i; j < (int)strlen(str); j++) /* if the wrap portion is */
  1745.         if (str[j]!=' ') break;        /* only space, don't wrap it*/
  1746.         if ((((strlen(str)-i)!=1) || (str[i]!='.')) && (j!=strlen(str)))
  1747.         draw_info(pl, (str+i));
  1748.         return;
  1749.     }
  1750.   }
  1751.   strncpy(pl->contr->info[pl->contr->infopos],str,pl->contr->infochars);
  1752.   pl->contr->info[pl->contr->infopos][pl->contr->infochars] = '\0';
  1753.   XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
  1754.     pl->contr->gc_info,FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,
  1755.     pl->contr->info[pl->contr->infopos],
  1756.     strlen(pl->contr->info[pl->contr->infopos]));
  1757.   pl->contr->infopos = (pl->contr->infopos+1)% pl->contr->infolines ;
  1758.   if(++(pl->contr->infoline)>=pl->contr->infolines){
  1759.     if (pl->contr->scroll) {
  1760.       XCopyArea(pl->contr->gdisp,pl->contr->win_info,pl->contr->win_info,
  1761.             pl->contr->gc_info,0,FONTHEIGHT,pl->contr->infochars*FONTWIDTH,
  1762.                 pl->contr->infolines*FONTHEIGHT,0,0);
  1763.       pl->contr->infoline--;
  1764.     }
  1765.     else
  1766.       pl->contr->infoline=0;
  1767.     pl->contr->infofull=1;
  1768.   }
  1769.   strncpy(pl->contr->info[pl->contr->infopos],blanks,pl->contr->infochars);
  1770.   pl->contr->info[pl->contr->infopos][pl->contr->infochars] = '\0';
  1771.   XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
  1772.         pl->contr->gc_info,FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,blanks,strlen(blanks));
  1773.   if(pl->contr->writing) {
  1774.     strncpy(pl->contr->info[pl->contr->infopos],
  1775.             pl->contr->write_buf,pl->contr->infochars);
  1776.     pl->contr->info[pl->contr->infopos][pl->contr->infochars] = '\0';
  1777.      
  1778.     XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
  1779.                      FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,
  1780.                      pl->contr->write_buf,pl->contr->writing);
  1781.   }
  1782.   if ((int)strlen(str) > (int)pl->contr->infochars)
  1783.     draw_info(pl,str+pl->contr->infochars);
  1784. }
  1785.  
  1786.  
  1787. /****************************************************************************
  1788.  *
  1789.  * Following set of functions are used when entering commands, passwords,
  1790.  * or any other thing that takes several characters.
  1791.  *
  1792.  * This will not be needed for new client/server mode
  1793.  *
  1794.  ****************************************************************************/
  1795. void delete_ch(object *pl) {
  1796.   if(pl->contr->no_echo&&pl->contr->writing==1) /* Can't delete that prompt */
  1797.     return;
  1798.   pl->contr->write_buf[--pl->contr->writing]='\0';
  1799.   pl->contr->info[pl->contr->infoline][pl->contr->writing]='\0';
  1800.  
  1801.   if(pl->type == PLAYER && pl->contr->eric_server > 0) {
  1802.     esrv_write_ch(pl->contr->eric_server,8);
  1803.     return;
  1804.   }
  1805.  
  1806.   XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
  1807.     (pl->contr->writing+1)*FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT," ",1);
  1808. }
  1809.  
  1810. void write_ch(object *pl,unsigned char key)
  1811. {
  1812.   char *c;
  1813.  
  1814.   if ((key < 32 || key > 127) && key != 8)
  1815.     return;
  1816.  
  1817.   if(pl->contr->writing>=pl->contr->infochars)
  1818.     return;
  1819.    if(key==8||key==127) {
  1820.     delete_ch(pl->contr->ob);
  1821.     return;
  1822.   }
  1823.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1824.     esrv_write_ch(pl->contr->eric_server,
  1825.                 pl->contr->no_echo ? '?' : key);
  1826.     pl->contr->write_buf[pl->contr->writing]=key;
  1827.     pl->contr->writing++;
  1828.     return;
  1829.   }
  1830.   c= &pl->contr->write_buf[pl->contr->writing];
  1831.   pl->contr->write_buf[pl->contr->writing]=key;
  1832.   if(pl->contr->writing>=pl->contr->infochars)
  1833.       return;
  1834.   pl->contr->write_buf[pl->contr->writing]=key;
  1835.  
  1836.   pl->contr->info[pl->contr->infoline][pl->contr->writing] =
  1837.     pl->contr->no_echo? '?': key;
  1838.     pl->contr->writing++;
  1839.  
  1840.   pl->contr->write_buf[pl->contr->writing]='\0';
  1841.   pl->contr->info[pl->contr->infoline][pl->contr->writing]='\0';  pl->contr->info[pl->contr->infoline][pl->contr->writing]='\0';
  1842.   if(pl->contr->no_echo)
  1843.     XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
  1844.       pl->contr->writing*FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,"?",1);
  1845.   else
  1846.     XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
  1847.       pl->contr->writing*FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,c,1);
  1848. }
  1849.  
  1850. void refresh_win_info(object *op) {
  1851.   draw_all_info(op);
  1852. }
  1853.  
  1854. void clear_win_info(object *op) {
  1855.   int i;
  1856.  
  1857.     /* don't clear if in scroll mode MSW (master@rahul.net) */
  1858.   if((op->type==PLAYER)  &&  (op->contr->scroll)) return;
  1859.  
  1860.   if (op->type == PLAYER && op->contr->eric_server > 0) {
  1861.     esrv_foo(op->contr->eric_server,"clear_win_info");
  1862.     return;
  1863.   }
  1864.  
  1865.   for(i=0;i<op->contr->infolines;i++) {
  1866.     (void) memset((void *)op->contr->info[i],' ',op->contr->infochars);
  1867.     op->contr->info[i][op->contr->infochars]='\0';
  1868.   }
  1869.   XClearWindow(op->contr->gdisp,op->contr->win_info);
  1870. /*refresh_win_info(op); */
  1871.   op->contr->infoline=0;
  1872.   op->contr->infopos=0;
  1873. }
  1874.  
  1875. void refresh(object *pl) {
  1876.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1877.     esrv_foo(pl->contr->eric_server,"refresh");
  1878.     return;
  1879.   }
  1880.   XClearWindow(pl->contr->gdisp,pl->contr->win_game);
  1881.   if(pl->contr->viewmap) {
  1882.     draw_map(pl);
  1883.     return;
  1884.   }
  1885.   refresh_map(pl->map);
  1886.   (void)memset((void *)pl->contr->drawn,'\0',
  1887.                sizeof(New_Face*)*(WINRIGHT-WINLEFT+1)*(WINLOWER-WINUPPER+1));
  1888.   draw(pl);
  1889. }
  1890.  
  1891. #define CD_DRAW_MAP
  1892. /* #define ALTERNATE_MM */ /* Small changes by Frank...experimental */
  1893.  
  1894. void draw_dots(object *op) {
  1895.   player *pl;
  1896.  
  1897.   if (op->type == PLAYER && op->contr->eric_server > 0) {
  1898.     esrv_foo(op->contr->eric_server,"draw_dots");
  1899.     return;
  1900.   }
  1901.   op->contr->viewmap^=2;
  1902.   if(op->contr->viewmap&2) {
  1903.     int i=0;
  1904.     XSetForeground(op->contr->gdisp,op->contr->gc_game,op->contr->gforeground);
  1905.     XSetBackground(op->contr->gdisp,op->contr->gc_game,op->contr->gbackground);
  1906.     for(pl=first_player;pl!=NULL;pl=pl->next) {
  1907.       if(pl->ob->map!=op->map)
  1908.         break;
  1909. #ifdef CD_DRAW_MAP
  1910.       XFillRectangle(op->contr->gdisp,op->contr->win_game,op->contr->gc_game,
  1911.                      2+op->contr->mapres*(pl->ob->x - op->contr->mapxmin),
  1912.                      2+op->contr->mapres*(pl->ob->y - op->contr->mapymin),
  1913.                      op->contr->mapres,op->contr->mapres);
  1914.       op->contr->mapdelx[i]=pl->ob->x - op->contr->mapxmin;
  1915.       op->contr->mapdely[i]=pl->ob->y - op->contr->mapymin;
  1916.       i++;
  1917. #else /* CD_DRAW_MAP */
  1918.       XFillRectangle(op->contr->gdisp,op->contr->win_game,op->contr->gc_game,
  1919.                      2+op->contr->mapres*pl->ob->x,
  1920.                      2+op->contr->mapres*pl->ob->y,
  1921.                      op->contr->mapres,op->contr->mapres);
  1922.       op->contr->mapdelx[i]=pl->ob->x,
  1923.       op->contr->mapdely[i]=pl->ob->y,
  1924.       i++;
  1925. #endif /* CD_DRAW_MAP */
  1926.     }
  1927.     op->contr->mapdelx[i]= -1;
  1928.   } else {
  1929.     int i;
  1930.     XSetForeground(op->contr->gdisp,op->contr->gc_game,op->contr->gbackground);
  1931.     XSetBackground(op->contr->gdisp,op->contr->gc_game,op->contr->gforeground);
  1932.     for(i=0;op->contr->mapdelx[i]!=-1;i++)
  1933.       XFillRectangle(op->contr->gdisp,op->contr->win_game,op->contr->gc_game,
  1934.                      2+op->contr->mapres*op->contr->mapdelx[i],
  1935.                      2+op->contr->mapres*op->contr->mapdely[i],
  1936.                      op->contr->mapres,op->contr->mapres);
  1937.     XSetForeground(op->contr->gdisp,op->contr->gc_game,op->contr->gforeground);
  1938.     XSetBackground(op->contr->gdisp,op->contr->gc_game,op->contr->gbackground);
  1939.   }
  1940. }
  1941.     
  1942.  
  1943.     
  1944. #ifndef CD_DRAW_MAP
  1945.  
  1946. void draw_map(object *pl) {
  1947.   int res,x,y;
  1948.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  1949.     esrv_foo(pl->contr->eric_server,"draw_map");
  1950.     return;
  1951.   }
  1952.   pl->contr->viewmap=1;
  1953.   XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  1954.   XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
  1955.   XClearWindow(pl->contr->gdisp,pl->contr->win_game);
  1956.   res=(WINRIGHT-WINLEFT+1)*24/
  1957.       (pl->map->mapx>pl->map->mapy?pl->map->mapx:pl->map->mapy);
  1958.   pl->contr->mapres=res;
  1959.   for(x=0;x<pl->map->mapx;x++)
  1960.     for(y=0;y<pl->map->mapy;y++)
  1961.       if(!blocks_view(pl->map,x,y)&&!wall(pl->map,x,y))
  1962.         XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
  1963.                        pl->contr->gc_game,2+res*x,2+res*y,res,res);
  1964.   XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
  1965.   XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  1966. }
  1967.  
  1968. #else /* CD_DRAW_MAP */
  1969. void magic_mapping_mark(object *pl, char *map_mark, int strength);
  1970. void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py);
  1971.  
  1972. /* The following function is a lot messier than it really should be,
  1973.  * but there is no real easy solution.
  1974.  *
  1975.  * One of the main causes is uses the crossfire font to draw the stipple
  1976.  * pattern.  This then means that the excess needs to be erased.  As things
  1977.  * stand now, the excess is erased, and things look ok.
  1978.  *
  1979.  * Also, display on black and white system is still not as good (useful)
  1980.  * as on a color system.  However, things are not too bad.  At present, there
  1981.  * are 4 possible outputs:  White, meaning a wall, black, meaning
  1982.  * nothing (or only floor), grey (stippled pattern), for any other objects
  1983.  * that do not have a black foreground, and another stippled patern for
  1984.  * objects that do have a black foreground.
  1985.  *
  1986.  * Display of the stipples is not perfect.  One of the stipples is just
  1987.  * a checkerboard pattern.  IF the resolution is odd, and two of these
  1988.  * are placed together, little imperfections in the matching shows up.
  1989.  * However, it doesn't affect the usefulness of the display much, and
  1990.  * I don't want to add more code to deal with making the stipple perfect.
  1991.  * This is because the second stipple pattern used has a different
  1992.  * repeat rate
  1993.  *
  1994.  * Mark Wedel (master@rahul.net)
  1995.  */
  1996.  
  1997. void draw_map(object *pl) 
  1998. {
  1999.   int res,x,y;
  2000.   char *map_mark = (char *) malloc(pl->map->mapx * pl->map->mapy);
  2001.   int xmin = pl->map->mapx, xmax = 0, ymin = pl->map->mapy, ymax = 0;
  2002.   XWindowAttributes win_info;
  2003.  
  2004.   memset(map_mark, 0, pl->map->mapx * pl->map->mapy);
  2005.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  2006.     esrv_foo(pl->contr->eric_server,"draw_map");
  2007.     return;
  2008.   }
  2009. #if 0 /* Hmm, why did this fail completely?  I want to see all of it! */
  2010.   if (WIZPASS(pl)) /* Toggle WIZPASS with 'W' in DM-mode */
  2011.   {
  2012.     (void) memset((void *)map_mark, 1, pl->map->mapx * pl->map->mapy);
  2013.     xmin = 0;
  2014.     xmax = pl->map->mapx - 1;
  2015.     ymin = 0;
  2016.     ymax = pl->map->mapy - 1;
  2017.   }
  2018.   else
  2019. #endif
  2020.   {
  2021.     magic_mapping_mark(pl, map_mark, 3);
  2022.     for(x = 0; x < pl->map->mapx; x++) {
  2023.       for(y = 0; y < pl->map->mapy; y++) {
  2024.         if (map_mark[x + pl->map->mapx * y]==1) {
  2025.       xmin = x < xmin ? x : xmin;
  2026.       xmax = x > xmax ? x : xmax;
  2027.       ymin = y < ymin ? y : ymin;
  2028.       ymax = y > ymax ? y : ymax;
  2029.         }
  2030.       }
  2031.     }
  2032.     xmin--;
  2033.     xmin = xmin < 0 ? 0 : xmin;
  2034.     xmax++;
  2035.     xmax = xmax > pl->map->mapx - 1 ? pl->map->mapx - 1: xmax;
  2036.     ymin--;
  2037.     ymin = ymin < 0 ? 0 : ymin;
  2038.     ymax++;
  2039.     ymax = ymax > pl->map->mapy - 1? pl->map->mapy - 1: ymax;
  2040.   }
  2041.  
  2042.   pl->contr->viewmap=1;
  2043.  
  2044.   /* If the width and height of the game window is stored someplace,
  2045.    * that should be used instead.  I just didn't see this information
  2046.    * anywhere.  We could just use the standard width/height
  2047.    * values, but if the window has been resized larger, things wouldn't
  2048.    * look right. - Mark Wedel
  2049.    */
  2050.    XGetWindowAttributes(pl->contr->gdisp, pl->contr->win_game, &win_info);
  2051.  
  2052.   /* If we have color, set for a grey background. From what I have seen,
  2053.    * grey isn't used much, so with the background grey, it should be easier
  2054.    * to tell what details magic mapping added - Mark Wedel 
  2055.    * (master@rahul.net)
  2056.    */
  2057.   if (pl->contr->iscolor) {
  2058.  
  2059.     XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->discolor[9].pixel);
  2060.     XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  2061.     XFillRectangle(pl->contr->gdisp, pl->contr->win_game, pl->contr->gc_game,
  2062.         0, 0, win_info.width, win_info.height);
  2063.   }
  2064.   else {
  2065.       XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
  2066.       XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  2067.       XClearWindow(pl->contr->gdisp,pl->contr->win_game);
  2068.   }
  2069.  
  2070.   res=(WINRIGHT-WINLEFT+1)*24/
  2071.     (xmax - xmin + 1 >  ymax - ymin + 1 ? xmax - xmin + 1 : ymax - ymin + 1); 
  2072.  
  2073.   /* The bitmap used for objects is only 24x24.  Too keep things simple,
  2074.    * so that we don't need to draw it several times, keep the maximum
  2075.    * resolution 24 pixels.  In general, only if magic mapping is mapping
  2076.    * a very small area will the resolution be greater than 24.
  2077.    * master@rahul.net
  2078.    */
  2079. #ifdef ALTERNATE_MM
  2080.   if (res > 24)
  2081.     res = 24;
  2082. #else
  2083.   if (!pl->contr->iscolor && res>24) res=24;
  2084. #endif
  2085.   pl->contr->mapres=res;
  2086.   pl->contr->mapxmin = xmin;
  2087.   pl->contr->mapymin = ymin;
  2088.  
  2089.   for (x = xmin; x <= xmax; x++) {
  2090.     for (y = ymin; y <= ymax; y++) {
  2091.       if (map_mark[x + pl->map->mapx * y]) {
  2092.  
  2093.         object *tmp_obj = get_map_ob(pl->map, x, y);
  2094.         New_Face *f = get_map(pl->map, x, y)->face;
  2095.  
  2096.         if (f!=blank_face) {
  2097.         while ((tmp_obj!=NULL) && (tmp_obj->face!=f))
  2098.             tmp_obj = tmp_obj->above;
  2099.  
  2100.         /* This shouldn't happen, but might as well check for it */
  2101.         if (tmp_obj==NULL) {
  2102.             fprintf(stderr, "Wasn't able to find floor, x=%d, y=%d (magic mapping)\n",x,y);
  2103.             continue;
  2104.         }
  2105.         }
  2106. /* This is more complicated than it should be, but..
  2107.  * If it is blank space, use the background color because the foreground
  2108.  *    color is some odd value that doesn't correspond to what the blank
  2109.  *    space looks like.
  2110.  * If the object is a wall or blocks the view, and the background is not
  2111.  *     the standard background color, use the background color to draw
  2112.  *    the object.  This is really so that the yellow walls (which are
  2113.  *    used on a lot of maps) are displayed properly.
  2114.  * If the object is a floor, and the foreground color is black, use the
  2115.  *    background.  This makes a lot of maps clearer.
  2116.  *
  2117.  * NOTE:  it is possible for tmp_obj to be NULL, but only when f==G_BLANK.
  2118.  * Because evaluation of the if statement will end with f==G_BLANK, this
  2119.  * is ok.  But this means that this if statement CAN NOT be re-ordered
  2120.  * so that IS_FLOOR is evaluated before f==G_BLANK is.
  2121.  *
  2122.  * Right now, a lot of objects use a black foreground (most weapon and
  2123.  * armor, as well as spell books, chairs, tables, ....)  If (as) these
  2124.  * items are colored with a different foreground color, magic mapping will
  2125.  * become even more useful.  However, I suppose there is only so much that
  2126.  * can be done with 12 colors.
  2127.  * 
  2128.  * Mark Wedel (master@rahul.net)
  2129.  */
  2130.     if (pl->contr->iscolor) {
  2131. #ifdef ALTERNATE_MM
  2132.             XSetForeground(pl->contr->gdisp, pl->contr->gc_game,
  2133.                            pl->contr->discolor[f->fg].pixel);
  2134.             XSetBackground(pl->contr->gdisp, pl->contr->gc_game,
  2135.                            pl->contr->discolor[f->bg].pixel);
  2136. #else /* ALTERNATE_MM */
  2137.         if (f->number==blank_face->number || 
  2138.         (map_mark[x+pl->map->mapx * y]==2 && f->bg!=12) ||
  2139.         (QUERY_FLAG(tmp_obj, FLAG_IS_FLOOR) && f->fg==0))
  2140.         XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
  2141.             pl->contr->discolor[f->bg].pixel);
  2142.         else
  2143.         XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
  2144.             pl->contr->discolor[f->fg].pixel);
  2145.         XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
  2146.                        pl->contr->gc_game, 2 + res*(x - xmin), 
  2147.                2 + res*(y - ymin), res, res);
  2148. #endif /* ALTERNATE_MM */
  2149.         }
  2150. #ifndef ALTERNATE_MM
  2151.         else
  2152. #endif /* ALTERNATE_MM */
  2153.     {/* if on black/white system */
  2154.         /* Above NOTE also applies for this if statement
  2155.          * Don't do any display for floors on b/w systems
  2156.          * However, if we aren't using pixmaps, erase the
  2157.          * space, because a stipple may have overwritten it
  2158.          */
  2159.         if (f->number==blank_face->number ||
  2160.            (!pl->contr->iscolor && QUERY_FLAG(tmp_obj, FLAG_IS_FLOOR))) {
  2161.             if (!pl->contr->use_pixmaps) {
  2162.             XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
  2163.             XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
  2164.                 pl->contr->gc_game, 2 + res*(x - xmin), 
  2165.                 2 + res*(y - ymin), res, res);
  2166.             XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  2167.             }
  2168.             continue;
  2169.         }
  2170.         if (!pl->contr->iscolor && map_mark[x + pl->map->mapx * y]==2)
  2171.             XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
  2172.                        pl->contr->gc_game, 2 + res*(x - xmin), 
  2173.                2 + res*(y - ymin), res, res);
  2174.         else {
  2175.             Fontindex use;
  2176.             
  2177. #ifdef ALTERNATE_MM
  2178.             if (!pl->contr->iscolor && itemcolor[f][0]==0)
  2179. #else /* ALTERNATE_MM */
  2180.             if (f->fg==0)
  2181. #endif /* ALTERNATE_MM */
  2182.             use = stipple2_face->number;
  2183.             else
  2184.             use = stipple1_face->number;
  2185.             if (pl->contr->use_pixmaps)
  2186.             XCopyPlane(pl->contr->gdisp, pl->contr->pixmaps[use],
  2187.                 pl->contr->win_game, pl->contr->gc_game,
  2188.                 0, 0, res,res, 2 + res*(x-xmin), 2+res*(y-ymin),
  2189.                 1);
  2190.             else {
  2191.             XChar buf= FontindexToXChar((Fontindex) use);
  2192.  
  2193.             XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
  2194.                 pl->contr->gc_game,2+res*(x-xmin),06+res*(y-ymin),&buf,1);
  2195.             }
  2196.         }
  2197.     }
  2198.       }
  2199.       else if (!pl->contr->iscolor && !pl->contr->use_pixmaps) {
  2200.     /* There is no easy way to draw only a portion of a font
  2201.      * character (at least that I saw.)  So, if we used the stipple
  2202.      * font to draw a character portion, we then need to erase the
  2203.      * extra portions that were drawn, and this code does that as
  2204.      * it encounters them.
  2205.      */
  2206.  
  2207.       XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
  2208.       XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
  2209.         pl->contr->gc_game, 2 + res*(x - xmin), 
  2210.         2 + res*(y - ymin), res, res);
  2211.       XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  2212.       }
  2213.     }
  2214.   }
  2215.   XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
  2216.   XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
  2217.  
  2218.   /* If black/white, and uses the font, erase the edges of the
  2219.    * window.  This is to remove any excess pattern that the font
  2220.    * might leave - master@rahul.net
  2221.    */
  2222.   if (!pl->contr->iscolor && !pl->contr->use_pixmaps) {
  2223.     XFillRectangle(pl->contr->gdisp, pl->contr->win_game, pl->contr->gc_game,
  2224.         (xmax+1-xmin)*res+2, 0, win_info.width - 2 - res*(xmax+1-xmin),
  2225.          win_info.height);
  2226.     XFillRectangle(pl->contr->gdisp, pl->contr->win_game, pl->contr->gc_game,
  2227.         0, 2+res*(ymax+1-ymin), win_info.width, win_info.height-2 -
  2228.         res*(ymax+1-ymin));
  2229.   }
  2230.   free(map_mark);
  2231. }
  2232.  
  2233. /* Note:  For improved magic mapping display, the space that blocks
  2234.  * the view is now marked with value 2.  Any dependencies of map_mark
  2235.  * being nonzero have been changed to check for 1.  Also, since
  2236.  * map_mark is a char value, putting 2 in should cause no problems.
  2237.  * Mark Wedel (master@rahul.net)
  2238.  */
  2239.  
  2240. void magic_mapping_mark(object *pl, char *map_mark, int strength)
  2241. {
  2242.   int x, y;
  2243.   int xmin = pl->x - strength + 1 < 0 ? 0 : pl->x - strength + 1;
  2244.   int xmax = pl->x + strength - 1 > pl->map->mapx - 1 ? 
  2245.     pl->map->mapx - 1 : pl->x + strength - 1;
  2246.   int ymin = pl->y - strength + 1 < 0 ? 0 : pl->y - strength + 1;
  2247.   int ymax = pl->y + strength - 1 > pl->map->mapy - 1 ? 
  2248.     pl->map->mapy - 1 : pl->y + strength - 1;
  2249.  
  2250.   for (x = xmin; x <= xmax; x++) {
  2251.     for (y = ymin; y <= ymax; y++) {
  2252.       if (wall(pl->map, x, y) || blocks_view(pl->map, x, y))
  2253.     map_mark[x + pl->map->mapx * y] = 2;
  2254.       else {
  2255.     map_mark[x + pl->map->mapx * y] = 1;
  2256.     magic_mapping_mark_recursive(pl, map_mark, x, y);
  2257.       }
  2258.     }
  2259.   }
  2260. }
  2261.  
  2262. void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py)
  2263. {
  2264.   int x, y, dx, dy;
  2265.  
  2266.   for (dx = -1; dx <= 1; dx++) {
  2267.     for (dy = -1; dy <= 1; dy++) {
  2268.       x = px + dx;
  2269.       y = py + dy;
  2270.       if (x >= 0 && x < pl->map->mapx && y >= 0 && y < pl->map->mapy
  2271.     && (map_mark[x + pl->map->mapx * y] ==0) ) {
  2272.             if (blocks_view(pl->map, x, y))
  2273.         map_mark[x + pl->map->mapx * y] = 2;
  2274.         else {
  2275.         if (wall(pl->map, x, y))
  2276.             map_mark[x + pl->map->mapx * y] = 2;
  2277.         else
  2278.             map_mark[x + pl->map->mapx * y] = 1;
  2279.         magic_mapping_mark_recursive(pl, map_mark, x, y);
  2280.         }
  2281.     }
  2282.     }
  2283.   }
  2284. }
  2285.  
  2286.  
  2287. #endif /* CD_DRAW_MAP */      
  2288.  
  2289. void draw(object *pl) {
  2290.   int i,j,last_f= -1,last_b= -1,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
  2291.   XChar buf;
  2292.   New_Face *f;
  2293.  
  2294.   if(pl->map == NULL || pl->map->in_memory != MAP_IN_MEMORY)
  2295.     return;
  2296.  
  2297.    if(pl->contr->viewmap) {
  2298.     draw_dots(pl);
  2299.     return;
  2300.   }
  2301.   if(pl->contr->do_los) {
  2302.     update_los(pl);
  2303. #ifdef USE_LIGHTING
  2304.     pl->map->do_los = 0;
  2305. #endif
  2306.     pl->contr->do_los = 0;
  2307.   }
  2308.  
  2309. #ifdef Xpm_Pix
  2310.   if (pl->contr->color_pixmaps) {
  2311.       draw_color_pix(pl);
  2312.       return;
  2313.   }
  2314. #endif
  2315.   if(pl->contr->use_pixmaps) {
  2316.     draw_pix(pl);
  2317.     return;
  2318.   }
  2319.   if(!pl->contr->iscolor) {
  2320.     draw_bw(pl); /* This function optimizes better */
  2321.     return;
  2322.   }
  2323.  
  2324.   /* The following looks like it only applies to bw systems using
  2325.    * the font.
  2326.    */
  2327.   buf= FontindexToXChar((Fontindex) 0);
  2328.   for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
  2329.     ay=j-pl->y-WINUPPER;
  2330.     for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
  2331.       ax=i-pl->x-WINLEFT;
  2332.       f = (out_of_map(pl->map,i,j)||
  2333.        pl->contr->blocked_los[i+5-pl->x][j+5-pl->y])?
  2334.            blocked_face : get_map(pl->map,i,j)->face;
  2335.       if(f!= pl->contr->drawn[ax][ay]) {
  2336.         buf=FontindexToXChar(f->number);
  2337.         pl->contr->drawn[ax][ay]=f;
  2338.         if(pl->contr->discolor[f->fg].pixel!=last_f)
  2339.           XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
  2340.                          (last_f=pl->contr->discolor[f->fg].pixel));
  2341.         if(pl->contr->discolor[f->bg].pixel!=last_b)
  2342.           XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
  2343.                            (last_b=pl->contr->discolor[f->bg].pixel));
  2344.         XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
  2345.                          pl->contr->gc_game,2+24*ax,ay*24+26,&buf,1);
  2346.       }
  2347.     }
  2348.   }
  2349.   if(pl->invisible & (pl->invisible<50 ? 4 : 1)) {
  2350.     pl->contr->drawn[5][5]=pl->face;
  2351.     buf=FontindexToXChar(pl->face->number);
  2352.     XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
  2353.       pl->contr->discolor[pl->face->fg].pixel);
  2354.     XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
  2355.       pl->contr->discolor[pl->face->bg].pixel);
  2356.     XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
  2357.                      pl->contr->gc_game,122,146,&buf,1);
  2358.     }
  2359. }
  2360.  
  2361. void draw_pix(object *pl) {
  2362.   int i,j,last_f= -1,last_b= -1,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
  2363.   New_Face *f;
  2364.  
  2365.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  2366.     esrv_foo(pl->contr->eric_server,"draw_pix");
  2367.     return;
  2368.   }
  2369.   if(pl->contr->viewmap) {
  2370.     draw_dots(pl);
  2371.     return;
  2372.   }
  2373.   for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
  2374.     ay=j-pl->y-WINUPPER;
  2375.     for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
  2376.       ax=i-pl->x-WINLEFT;
  2377.       f=(out_of_map(pl->map,i,j)||
  2378.      pl->contr->blocked_los[i+5-pl->x][j+5-pl->y])?
  2379.        blocked_face : get_map(pl->map,i,j)->face;
  2380.       if(f!=pl->contr->drawn[ax][ay]) {
  2381.         pl->contr->drawn[ax][ay]=f;
  2382.         if(pl->contr->iscolor) {
  2383.           if(pl->contr->discolor[f->fg].pixel!=last_f)
  2384.             XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
  2385.                            (last_f=pl->contr->discolor[f->fg].pixel));
  2386.           if(pl->contr->discolor[f->bg].pixel!=last_b)
  2387.             XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
  2388.                            (last_b=pl->contr->discolor[f->bg].pixel));
  2389.         }
  2390.         XCopyPlane(pl->contr->gdisp,pl->contr->pixmaps[f->number],
  2391.                    pl->contr->win_game,pl->contr->gc_game,
  2392.                    0,0,24,24,2+24*ax,2+24*ay,1);
  2393.       }
  2394.     }
  2395.   }
  2396.   if(pl->invisible & (pl->invisible < 50 ? 4 : 1)) {
  2397.     pl->contr->drawn[5][5] = pl->face;
  2398.     if(pl->contr->iscolor) {
  2399.       XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
  2400.         pl->contr->discolor[pl->face->fg].pixel);
  2401.       XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
  2402.         pl->contr->discolor[pl->face->bg].pixel);
  2403.     }
  2404.     XCopyPlane(pl->contr->gdisp,pl->contr->pixmaps[pl->face->number],
  2405.                pl->contr->win_game,pl->contr->gc_game,0,0,24,24,122,122,1);
  2406.   }
  2407. }
  2408.  
  2409. void draw_bw(object *pl) {
  2410.   int i,j,left,right,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
  2411.   XChar buff[20];
  2412.   New_Face *tmp;
  2413.  
  2414.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  2415.     esrv_foo(pl->contr->eric_server,"draw_bw");
  2416.     return;
  2417.   }
  2418.   for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
  2419.     left= -1,right=0,ay=j-pl->y-WINUPPER;
  2420.     for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
  2421.       ax=i-pl->x-WINLEFT;
  2422.       tmp = (out_of_map(pl->map,i,j)||
  2423.          pl->contr->blocked_los[i+5-pl->x][j+5-pl->y]) ?
  2424.          blocked_face : get_map(pl->map,i,j)->face;
  2425.       if(tmp!=pl->contr->drawn[ax][ay]) {
  2426.       pl->contr->drawn[ax][ay]=tmp;
  2427.       if(left== (-1)) left=ax;
  2428.       right=ax;
  2429.       }
  2430.       buff[ax] = FontindexToXChar(tmp->number);
  2431.     }
  2432.     if(left!=-1)
  2433.       XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
  2434.                        pl->contr->gc_game,2+24*left,ay*24+26,buff+left,
  2435.                right-left+1);
  2436.   }
  2437.   if(pl->invisible & (pl->invisible < 50 ? 4 : 1)) {
  2438.     buff[0]=FontindexToXChar(pl->face->number);
  2439.     pl->contr->drawn[5][5] = pl->face;
  2440.     XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
  2441.              pl->contr->gc_game,122,122,buff,1);
  2442.   }
  2443. }
  2444.  
  2445. #ifdef Xpm_Pix  
  2446. void draw_client_map(object *pl)
  2447. {
  2448.     int i,j,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
  2449.     New_Face    *face,*floor;
  2450. #ifdef DOUBLE_FLOOR
  2451.     New_Face    *floor2;
  2452. #endif
  2453.  
  2454.   if (pl->type == PLAYER && pl->contr->eric_server > 0) {
  2455.     esrv_map_new(pl->contr->eric_server); /* implicitly clears all cells */
  2456.     if(pl->invisible & (pl->invisible < 50 ? 4 : 1)) {
  2457.       esrv_map_setbelow(pl->contr->eric_server,5,5,pl->face->number);
  2458.     }
  2459.     for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
  2460.       ay=j-pl->y-WINUPPER;
  2461.       for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
  2462.         ax=i-pl->x-WINLEFT;
  2463.       if (!(out_of_map(pl->map,i,j) ||
  2464.           pl->contr->blocked_los[i+5-pl->x][j+5-pl->y])) {
  2465.         face = get_map(pl->map, i, j)->face;
  2466.         floor = get_map_floor(pl->map, i,j)->face;
  2467. #ifdef DOUBLE_FLOOR
  2468.         floor2 = get_map_floor2(pl->map, i,j)->face;
  2469. #endif
  2470.         if (face == blank_face &&
  2471. #ifdef DOUBLE_FLOOR
  2472.         floor2 == blank_face &&
  2473. #endif
  2474.             floor == blank_face) {
  2475.           esrv_map_setbelow(pl->contr->eric_server,ax,ay,blank_face->number);
  2476.         } else {
  2477.           if (face != blank_face)
  2478.             esrv_map_setbelow(pl->contr->eric_server,ax,ay,face->number);
  2479. #ifdef DOUBLE_FLOOR
  2480.           if (floor2 != blank_face)
  2481.             esrv_map_setbelow(pl->contr->eric_server,ax,ay,floor2->number);
  2482. #endif
  2483.           if (floor != blank_face)
  2484.             esrv_map_setbelow(pl->contr->eric_server,ax,ay,floor->number);
  2485.         }
  2486.       }
  2487.       }
  2488.     }
  2489.     esrv_map_doneredraw(pl->contr->eric_server);
  2490.     return;
  2491.   }
  2492. }
  2493.  
  2494. /* draw_color_pix is orignally from draw_pix.  I separated them for reasons
  2495.  * of speed.  The main differences are these:  Color pixmaps do not need
  2496.  * foreground and background set (it does nothing), but does need
  2497.  * to set the bitmask for objects.
  2498.  *
  2499.  * Because of shape masks, this function has become a little more complicated,
  2500.  * and probably slower.  The other option is to keep it like draw_pix and
  2501.  * the other draw functions, and only draw the top object.  However, I think
  2502.  * one of the advantages of the color pixmaps is that you do have a shape
  2503.  * mask, and it would be a shame not to use it.
  2504.  *
  2505.  * A re-draw is done only if the top object on a square is changed.
  2506.  *`As far as I know, floors can not really change unless someone moves
  2507.  * on top of them, so this should work fine.
  2508.  * An exception to this is the player, as he can move in the same direction.
  2509.  * His face remains the same, but the floor underneath him changes.
  2510.  *
  2511.  * One thought to perhaps make the function quicker and reduce flicker
  2512.  * would be to draw all the floors on the first pass, then come back and
  2513.  * draw the objects.  This should be quicker, because the floors should
  2514.  * not need any of the clipmasks.
  2515.  * The best way to reduce flicker would probably be to draw both the
  2516.  * floor and object into a new pixmap, and then draw that pixmap onto
  2517.  * the screen.  It might even be a little quicker, because the ClipOrigin
  2518.  * should only need to be set once.
  2519.  */
  2520.  
  2521. /* New version of draw_color_pix.  This should hopefully run faster and
  2522.  * with less jittering than the old routine.  It does cost a little more
  2523.  * memory (2 gc's and a 24x24 pixmap added to the player structure.)
  2524.  * The gc's have some values pre-set so that this routine does not need to
  2525.  * set them for each pixmap drawn.
  2526.  */
  2527. void draw_color_pix(object *pl) {
  2528.     int i,j,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
  2529.     New_Face    *face,*floor;
  2530. #ifdef DOUBLE_FLOOR
  2531.     New_Face    *floor2;
  2532. #endif
  2533.     static Pixmap    obj_mask = 0;
  2534.  
  2535.     if (pl->contr->eric_server>0) {
  2536.     draw_client_map(pl);
  2537.     return;
  2538.     }
  2539.  
  2540.     for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
  2541.       ay=j-pl->y-WINUPPER;
  2542.       for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
  2543.         ax=i-pl->x-WINLEFT;
  2544.     if (out_of_map(pl->map,i,j) ||
  2545.       pl->contr->blocked_los[i+5-pl->x][j+5-pl->y]) {
  2546.         if (pl->contr->drawn[ax][ay]!=blocked_face) {
  2547.  
  2548.         /* A XClearArea is probably faster than copying the pixmap.
  2549.          * (it also works better)
  2550.          * Also, this way we do not need to worry about any masking
  2551.          * values.  
  2552.          * What might be better is to detect which cooridnate (i or j)
  2553.          * is out of bounds of the map.  Since all maps are square,
  2554.          * then one XClearArea could be used to clear the entire
  2555.          * row or column, and then break out.  This would
  2556.          * skip several checks.
  2557.          * Mark Wedel (master@rahul.net)
  2558.          */
  2559.         XClearArea(pl->contr->gdisp, pl->contr->win_game,
  2560.             2+24*ax, 2+24*ay, 24, 24, False);
  2561.             pl->contr->drawn[ax][ay] = blocked_face;
  2562.         }
  2563.       }
  2564.     else {
  2565.       face = get_map(pl->map, i, j)->face;
  2566.       floor = get_map_floor(pl->map, i,j)->face;
  2567. #ifdef DOUBLE_FLOOR
  2568.       floor2 = get_map_floor2(pl->map, i,j)->face;
  2569.       if (face!=pl->contr->drawn[ax][ay] ||
  2570.           floor!=pl->contr->floor[ax][ay] ||
  2571.           floor2!=pl->contr->floor2[ax][ay]) {
  2572. #else
  2573.       if (face!=pl->contr->drawn[ax][ay] ||
  2574.           floor!=pl->contr->floor[ax][ay]) {
  2575. #endif
  2576.           XCopyArea(pl->contr->gdisp, pl->contr->pixmaps[floor->number],
  2577.             pl->contr->xpm_pixmap, pl->contr->gc_xpm_floor,
  2578.             0, 0, 24, 24, 0, 0);
  2579. #ifdef DOUBLE_FLOOR
  2580.         /* If there is a second FLOOR_TYPE item on top of the
  2581.          * first, draw it with the right clipmask. This looks
  2582.          * good, but may be expensive as 3 pixmaps are drawn
  2583.          * instead of 2.
  2584.          * Gregor Schmid (schmid@fb3-s7.math.tu-berlin.de)
  2585.          */
  2586.         if (floor2 != blank_face) {
  2587.                 XSetClipMask(pl->contr->gdisp,
  2588.                      pl->contr->gc_xpm_floor,
  2589.                      pl->contr->masks[floor2->number]);
  2590.             XCopyArea(pl->contr->gdisp,
  2591.                   pl->contr->pixmaps[floor2->number],
  2592.                   pl->contr->xpm_pixmap,pl->contr->gc_xpm_floor,
  2593.                   0,0,24,24,0, 0);
  2594.                 XSetClipMask(pl->contr->gdisp,
  2595.                      pl->contr->gc_xpm_floor,None);
  2596.         }
  2597. #endif
  2598.         if (obj_mask != pl->contr->masks[face->number]) {
  2599.               XSetClipMask(pl->contr->gdisp, pl->contr->gc_xpm_object,
  2600.             pl->contr->masks[face->number]);
  2601.           obj_mask = pl->contr->masks[face->number];
  2602.         }
  2603.             XCopyArea(pl->contr->gdisp,pl->contr->pixmaps[face->number],
  2604.                     pl->contr->xpm_pixmap,pl->contr->gc_xpm_object,
  2605.                     0,0,24,24,0, 0);
  2606.             XCopyArea(pl->contr->gdisp,pl->contr->xpm_pixmap,
  2607.                     pl->contr->win_game,pl->contr->gc_game,
  2608.                     0,0,24,24,2+24*ax,2+24*ay);
  2609.             pl->contr->floor[ax][ay] = floor;
  2610.         pl->contr->drawn[ax][ay]= face;
  2611. #ifdef DOUBLE_FLOOR
  2612.             pl->contr->floor2[ax][ay] = floor2;
  2613. #endif
  2614.       }
  2615.     }
  2616.       }
  2617.     }
  2618.    if(pl->invisible && (pl->invisible < 50 ? 4 : 1)) {
  2619.      pl->contr->drawn[5][5] = pl->face;
  2620.      XCopyArea(pl->contr->gdisp,pl->contr->pixmaps[pl->face->number],
  2621.                 pl->contr->win_game,pl->contr->gc_game,0,0,24,24,122,122);
  2622.    }
  2623. }
  2624. #endif
  2625.